18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/random.h> 78c2ecf20Sopenharmony_ci#include "kvmcpu.h" 88c2ecf20Sopenharmony_ci#include "kvm_compat.h" 98c2ecf20Sopenharmony_ci#include "ls3a_ipi.h" 108c2ecf20Sopenharmony_ci#include "ls7a_irq.h" 118c2ecf20Sopenharmony_ci#include "ls3a_ext_irq.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define ls3a_ext_irq_lock(s, flags) spin_lock_irqsave(&s->lock, flags) 148c2ecf20Sopenharmony_ci#define ls3a_ext_irq_unlock(s, flags) spin_unlock_irqrestore(&s->lock, flags) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciextern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, 178c2ecf20Sopenharmony_ci struct kvm_loongarch_interrupt *irq); 188c2ecf20Sopenharmony_civoid ext_deactive_core_isr(struct kvm *kvm, int irq_num, int vcpu_id) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int ipnum; 218c2ecf20Sopenharmony_ci unsigned long found1; 228c2ecf20Sopenharmony_ci struct kvm_loongarch_interrupt irq; 238c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 248c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci ipnum = state->ext_sw_ipmap[irq_num]; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_isr.reg_u8, irq_num, 1); 298c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 328c2ecf20Sopenharmony_ci found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 338c2ecf20Sopenharmony_ci kvm_debug("vcpu_id %d irqnum %d found:0x%lx ipnum %d down\n", vcpu_id, irq_num, found1, ipnum); 348c2ecf20Sopenharmony_ci if (found1 == EXTIOI_IRQS) { 358c2ecf20Sopenharmony_ci irq.cpu = vcpu_id; 368c2ecf20Sopenharmony_ci irq.irq = -(ipnum + 2); /* IP2~IP5 */ 378c2ecf20Sopenharmony_ci if (likely(kvm->vcpus[vcpu_id])) 388c2ecf20Sopenharmony_ci kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 398c2ecf20Sopenharmony_ci kvm->stat.trigger_ls3a_ext_irq++; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * ext_irq_update_core() 458c2ecf20Sopenharmony_ci * @kvm: KVM structure pointer 468c2ecf20Sopenharmony_ci * @irq_num: 0~256 ext irq num 478c2ecf20Sopenharmony_ci * @level: 0~1 High and low level 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Route the status of the extended interrupt to the host CPU core. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_civoid ext_irq_update_core(struct kvm *kvm, int irq_num, int level) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int nrcpus, ipnum, vcpu_id; 558c2ecf20Sopenharmony_ci unsigned long found1; 568c2ecf20Sopenharmony_ci struct kvm_loongarch_interrupt irq; 578c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 588c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci nrcpus = atomic_read(&kvm->online_vcpus); 618c2ecf20Sopenharmony_ci vcpu_id = state->ext_sw_coremap[irq_num]; 628c2ecf20Sopenharmony_ci ipnum = state->ext_sw_ipmap[irq_num]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (vcpu_id > (nrcpus - 1)) { 658c2ecf20Sopenharmony_ci vcpu_id = 0; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (level == 1) { 698c2ecf20Sopenharmony_ci if (test_bit(irq_num, (void *)state->ext_en.reg_u8) == false) { 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci if (test_bit(irq_num, (void *)state->ext_isr.reg_u8) == false) { 738c2ecf20Sopenharmony_ci return; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci bitmap_set((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 788c2ecf20Sopenharmony_ci bitmap_set((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 798c2ecf20Sopenharmony_ci kvm_debug("%s:%d --- vcpu_id %d irqnum %d found1 0x%lx ipnum %d\n", 808c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, vcpu_id, irq_num, found1, ipnum); 818c2ecf20Sopenharmony_ci if (found1 == EXTIOI_IRQS) { 828c2ecf20Sopenharmony_ci irq.cpu = vcpu_id; 838c2ecf20Sopenharmony_ci irq.irq = ipnum + 2; /* IP2~IP5 */ 848c2ecf20Sopenharmony_ci kvm_debug("%s:%d --- vcpu_id %d ipnum %d raise\n", 858c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, vcpu_id, ipnum); 868c2ecf20Sopenharmony_ci if (likely(kvm->vcpus[vcpu_id])) 878c2ecf20Sopenharmony_ci kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 888c2ecf20Sopenharmony_ci kvm->stat.trigger_ls3a_ext_irq++; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } else { 918c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_isr.reg_u8, irq_num, 1); 928c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_core_isr.reg_u8[vcpu_id], irq_num, 1); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], irq_num, 1); 958c2ecf20Sopenharmony_ci found1 = find_next_bit((void *)state->ext_sw_ipisr[vcpu_id][ipnum + 2], EXTIOI_IRQS, 0); 968c2ecf20Sopenharmony_ci if (found1 == EXTIOI_IRQS) { 978c2ecf20Sopenharmony_ci irq.cpu = vcpu_id; 988c2ecf20Sopenharmony_ci irq.irq = -(ipnum + 2); /* IP2~IP5 */ 998c2ecf20Sopenharmony_ci if (likely(kvm->vcpus[vcpu_id])) 1008c2ecf20Sopenharmony_ci kvm_vcpu_ioctl_interrupt(kvm->vcpus[vcpu_id], &irq); 1018c2ecf20Sopenharmony_ci kvm->stat.trigger_ls3a_ext_irq++; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid msi_irq_handler(struct kvm *kvm, int irq, int level) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci unsigned long flags; 1108c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = ls3a_ext_irqchip(kvm); 1118c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = &(s->ls3a_ext_irq); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci kvm_debug("ext_irq_handler:irq = %d,level = %d\n", irq, level); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(s, flags); 1168c2ecf20Sopenharmony_ci if (level == 1) { 1178c2ecf20Sopenharmony_ci if (test_bit(irq, (void *)&state->ext_isr)) 1188c2ecf20Sopenharmony_ci goto out; 1198c2ecf20Sopenharmony_ci __set_bit(irq, (void *)&state->ext_isr); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci if (!test_bit(irq, (void *)&state->ext_isr)) 1228c2ecf20Sopenharmony_ci goto out; 1238c2ecf20Sopenharmony_ci __clear_bit(irq, (void *)&state->ext_isr); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, irq, level); 1278c2ecf20Sopenharmony_ciout: 1288c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(s, flags); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_readb(struct kvm_vcpu *vcpu, 1328c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 1338c2ecf20Sopenharmony_ci gpa_t addr, void *val) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci uint64_t offset, reg_count; 1368c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 1378c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 1388c2ecf20Sopenharmony_ci int vcpu_id; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 1478c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START); 1488c2ecf20Sopenharmony_ci *(uint8_t *)val = state->ext_en.reg_u8[reg_count]; 1498c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 1508c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START); 1518c2ecf20Sopenharmony_ci *(uint8_t *)val = state->bounce.reg_u8[reg_count]; 1528c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 1538c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START); 1548c2ecf20Sopenharmony_ci *(uint8_t *)val = state->ext_isr.reg_u8[reg_count]; 1558c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 1568c2ecf20Sopenharmony_ci /* percpu(32 bytes) coreisr reg_count is 0~31 */ 1578c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 1588c2ecf20Sopenharmony_ci reg_count = offset & 0xff; 1598c2ecf20Sopenharmony_ci *(uint8_t *)val = state->ext_core_isr.reg_u8[vcpu_id][reg_count]; 1608c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 1618c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_IPMAP_START); 1628c2ecf20Sopenharmony_ci *(uint8_t *)val = state->ip_map.reg_u8[reg_count]; 1638c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 1648c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_COREMAP_START); 1658c2ecf20Sopenharmony_ci *(uint8_t *)val = state->core_map.reg_u8[reg_count]; 1668c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 1678c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START); 1688c2ecf20Sopenharmony_ci *(uint8_t *)val = state->node_type.reg_u8[reg_count]; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%x\n", 1718c2ecf20Sopenharmony_ci __FUNCTION__, addr, *(uint8_t *)val); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_readw(struct kvm_vcpu *vcpu, 1768c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 1778c2ecf20Sopenharmony_ci gpa_t addr, void *val) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci uint64_t offset, reg_count; 1808c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 1818c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 1828c2ecf20Sopenharmony_ci int vcpu_id; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 1918c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START) / 4; 1928c2ecf20Sopenharmony_ci *(uint32_t *)val = state->ext_en.reg_u32[reg_count]; 1938c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 1948c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START) / 4; 1958c2ecf20Sopenharmony_ci *(uint32_t *)val = state->bounce.reg_u32[reg_count]; 1968c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 1978c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START) / 4; 1988c2ecf20Sopenharmony_ci *(uint32_t *)val = state->ext_isr.reg_u32[reg_count]; 1998c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 2008c2ecf20Sopenharmony_ci /* percpu(32 bytes) coreisr reg_count is 0~7*/ 2018c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 2028c2ecf20Sopenharmony_ci reg_count = (offset & 0xff) / 4; 2038c2ecf20Sopenharmony_ci *(uint32_t *)val = state->ext_core_isr.reg_u32[vcpu_id][reg_count]; 2048c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 2058c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_IPMAP_START) / 4; 2068c2ecf20Sopenharmony_ci *(uint32_t *)val = state->ip_map.reg_u32[reg_count]; 2078c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 2088c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_COREMAP_START) / 4; 2098c2ecf20Sopenharmony_ci *(uint32_t *)val = state->core_map.reg_u32[reg_count]; 2108c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 2118c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START) / 4; 2128c2ecf20Sopenharmony_ci *(uint32_t *)val = state->node_type.reg_u32[reg_count]; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%x\n", 2158c2ecf20Sopenharmony_ci __FUNCTION__, addr, *(uint32_t *)val); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_readl(struct kvm_vcpu *vcpu, 2218c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 2228c2ecf20Sopenharmony_ci gpa_t addr, void *val) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci uint64_t offset, reg_count; 2258c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 2268c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 2278c2ecf20Sopenharmony_ci int vcpu_id; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 2368c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START) / 8; 2378c2ecf20Sopenharmony_ci *(uint64_t *)val = state->ext_en.reg_u64[reg_count]; 2388c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 2398c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START) / 8; 2408c2ecf20Sopenharmony_ci *(uint64_t *)val = state->bounce.reg_u64[reg_count]; 2418c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 2428c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START) / 8; 2438c2ecf20Sopenharmony_ci *(uint64_t *)val = state->ext_isr.reg_u64[reg_count]; 2448c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 2458c2ecf20Sopenharmony_ci /* percpu(32 bytes) coreisr reg_count is 0~3*/ 2468c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 2478c2ecf20Sopenharmony_ci reg_count = (offset & 0xff) / 8; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci *(uint64_t *)val = state->ext_core_isr.reg_u64[vcpu_id][reg_count]; 2508c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 2518c2ecf20Sopenharmony_ci *(uint64_t *)val = state->ip_map.reg_u64; 2528c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 2538c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_COREMAP_START) / 8; 2548c2ecf20Sopenharmony_ci *(uint64_t *)val = state->core_map.reg_u64[reg_count]; 2558c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 2568c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START) / 8; 2578c2ecf20Sopenharmony_ci *(uint64_t *)val = state->node_type.reg_u64[reg_count]; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%llx\n", 2608c2ecf20Sopenharmony_ci __FUNCTION__, addr, *(uint64_t *)val); 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * ls3a_ext_intctl_read() 2658c2ecf20Sopenharmony_ci * @kvm: KVM structure pointer 2668c2ecf20Sopenharmony_ci * @addr: Register address 2678c2ecf20Sopenharmony_ci * @size: The width of the register to be read. 2688c2ecf20Sopenharmony_ci * @val: The pointer to the read result. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Analog extended interrupt related register read. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_read(struct kvm_vcpu *vcpu, 2748c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 2758c2ecf20Sopenharmony_ci gpa_t addr, int size, void *val) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 2788c2ecf20Sopenharmony_ci unsigned long flags; 2798c2ecf20Sopenharmony_ci uint64_t offset; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 2848c2ecf20Sopenharmony_ci if (offset & (size - 1)) { 2858c2ecf20Sopenharmony_ci printk("%s:unaligned address access %llx size %d\n", 2868c2ecf20Sopenharmony_ci __FUNCTION__, addr, size); 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci addr = (addr & 0xfffff) - EXTIOI_ADDR_OFF; 2908c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(s, flags); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci switch (size) { 2938c2ecf20Sopenharmony_ci case 1: 2948c2ecf20Sopenharmony_ci ls3a_ext_intctl_readb(vcpu, dev, addr, val); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case 4: 2978c2ecf20Sopenharmony_ci ls3a_ext_intctl_readw(vcpu, dev, addr, val); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case 8: 3008c2ecf20Sopenharmony_ci ls3a_ext_intctl_readl(vcpu, dev, addr, val); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci default: 3038c2ecf20Sopenharmony_ci WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx, size %d\n", 3048c2ecf20Sopenharmony_ci __FUNCTION__, addr, size); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(s, flags); 3078c2ecf20Sopenharmony_ci kvm_debug("%s(%d):address access %llx size %d\n", 3088c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, offset, size); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_writeb(struct kvm_vcpu *vcpu, 3148c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 3158c2ecf20Sopenharmony_ci gpa_t addr, const void *__val) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci uint64_t offset, reg_count; 3188c2ecf20Sopenharmony_ci uint8_t val_data_u8, old_data_u8; 3198c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 3208c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 3218c2ecf20Sopenharmony_ci struct kvm *kvm = NULL; 3228c2ecf20Sopenharmony_ci int mask, level, i, irqnum, ipnum; 3238c2ecf20Sopenharmony_ci int vcpu_id; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci unsigned long val = *(unsigned long *)__val; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 3308c2ecf20Sopenharmony_ci kvm = s->kvm; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 3338c2ecf20Sopenharmony_ci val_data_u8 = val & 0xffUL; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 3388c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START); 3398c2ecf20Sopenharmony_ci old_data_u8 = state->ext_en.reg_u8[reg_count]; 3408c2ecf20Sopenharmony_ci if (old_data_u8 != val_data_u8) { 3418c2ecf20Sopenharmony_ci state->ext_en.reg_u8[reg_count] = val_data_u8; 3428c2ecf20Sopenharmony_ci old_data_u8 = old_data_u8 ^ val_data_u8; 3438c2ecf20Sopenharmony_ci mask = 0x1; 3448c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3458c2ecf20Sopenharmony_ci if (old_data_u8 & mask) { 3468c2ecf20Sopenharmony_ci level = !!(val_data_u8 & (0x1 << i)); 3478c2ecf20Sopenharmony_ci if (level) 3488c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 8, level); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci mask = mask << 1; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 3548c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START); 3558c2ecf20Sopenharmony_ci state->bounce.reg_u8[reg_count] = val_data_u8; 3568c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 3578c2ecf20Sopenharmony_ci /*can not be writen*/ 3588c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START) & 0x1f; 3598c2ecf20Sopenharmony_ci old_data_u8 = state->ext_isr.reg_u8[reg_count]; 3608c2ecf20Sopenharmony_ci state->ext_isr.reg_u8[reg_count] = old_data_u8 & (~val_data_u8); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci mask = 0x1; 3638c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3648c2ecf20Sopenharmony_ci if ((old_data_u8 & mask) && (val_data_u8 & mask)) { 3658c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 8, 0); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci mask = mask << 1; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 3718c2ecf20Sopenharmony_ci int bits; 3728c2ecf20Sopenharmony_ci /* percpu(32 bytes) coreisr reg_count is 0~31 */ 3738c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 3748c2ecf20Sopenharmony_ci reg_count = offset & 0xff; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci state->ext_core_isr.reg_u8[vcpu_id][reg_count] &= ~val_data_u8; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci bits = sizeof(val_data_u8) * 8; 3798c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u8, bits); 3808c2ecf20Sopenharmony_ci while (i < bits) { 3818c2ecf20Sopenharmony_ci ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 3828c2ecf20Sopenharmony_ci bitmap_clear((void *)&val_data_u8, i, 1); 3838c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u8, bits); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 3868c2ecf20Sopenharmony_ci /*drop arch.core_ip_mask use state->ip_map*/ 3878c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_IPMAP_START); 3888c2ecf20Sopenharmony_ci state->ip_map.reg_u8[reg_count] = val_data_u8; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ipnum = 0; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 3938c2ecf20Sopenharmony_ci if (val_data_u8 & (0x1 << i)) { 3948c2ecf20Sopenharmony_ci ipnum = i; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (val_data_u8) { 4008c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 4018c2ecf20Sopenharmony_ci irqnum = reg_count * 32 + i; 4028c2ecf20Sopenharmony_ci state->ext_sw_ipmap[irqnum] = ipnum; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } else { 4058c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 4068c2ecf20Sopenharmony_ci irqnum = reg_count * 32 + i; 4078c2ecf20Sopenharmony_ci state->ext_sw_ipmap[irqnum] = 0; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 4118c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_COREMAP_START); 4128c2ecf20Sopenharmony_ci state->core_map.reg_u8[reg_count] = val_data_u8; 4138c2ecf20Sopenharmony_ci state->ext_sw_coremap[reg_count] = val_data_u8; 4148c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 4158c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START); 4168c2ecf20Sopenharmony_ci state->node_type.reg_u8[reg_count] = val_data_u8; 4178c2ecf20Sopenharmony_ci } else { 4188c2ecf20Sopenharmony_ci WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx\n", 4198c2ecf20Sopenharmony_ci __FUNCTION__, addr); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_writew(struct kvm_vcpu *vcpu, 4268c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 4278c2ecf20Sopenharmony_ci gpa_t addr, const void *__val) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci uint64_t offset, reg_count; 4308c2ecf20Sopenharmony_ci uint32_t val_data_u32, old_data_u32, mask; 4318c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 4328c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 4338c2ecf20Sopenharmony_ci struct kvm *kvm = NULL; 4348c2ecf20Sopenharmony_ci uint8_t tmp_data_u8; 4358c2ecf20Sopenharmony_ci int i, level, vcpu_id; 4368c2ecf20Sopenharmony_ci unsigned long val; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci val = *(unsigned long *)__val; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 4438c2ecf20Sopenharmony_ci kvm = s->kvm; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 4468c2ecf20Sopenharmony_ci val_data_u32 = val & 0xffffffffUL; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 4518c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START) / 4; 4528c2ecf20Sopenharmony_ci old_data_u32 = state->ext_en.reg_u32[reg_count]; 4538c2ecf20Sopenharmony_ci if (old_data_u32 != val_data_u32) { 4548c2ecf20Sopenharmony_ci state->ext_en.reg_u32[reg_count] = val_data_u32; 4558c2ecf20Sopenharmony_ci old_data_u32 = old_data_u32 ^ val_data_u32; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mask = 0x1; 4588c2ecf20Sopenharmony_ci for (i = 0; i < 8 * sizeof(old_data_u32); i++) { 4598c2ecf20Sopenharmony_ci if (old_data_u32 & mask) { 4608c2ecf20Sopenharmony_ci level = !!(val_data_u32 & (0x1 << i)); 4618c2ecf20Sopenharmony_ci if (level) 4628c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 32, level); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci mask = mask << 1; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 4688c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START) / 4; 4698c2ecf20Sopenharmony_ci state->bounce.reg_u32[reg_count] = val_data_u32; 4708c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 4718c2ecf20Sopenharmony_ci /*can not be writen*/ 4728c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START) / 4; 4738c2ecf20Sopenharmony_ci old_data_u32 = state->ext_isr.reg_u32[reg_count]; 4748c2ecf20Sopenharmony_ci state->ext_isr.reg_u32[reg_count] = old_data_u32 & (~val_data_u32); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mask = 0x1; 4778c2ecf20Sopenharmony_ci for (i = 0; i < 8 * sizeof(old_data_u32); i++) { 4788c2ecf20Sopenharmony_ci if ((old_data_u32 & mask) && (val_data_u32 & mask)) { 4798c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 32, 0); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci mask = mask << 1; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 4848c2ecf20Sopenharmony_ci int bits; 4858c2ecf20Sopenharmony_ci /* percpu(32 bytes) coreisr reg_count is 0~7*/ 4868c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 4878c2ecf20Sopenharmony_ci reg_count = (offset & 0xff) / 4; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /*ext_core_ioisr*/ 4908c2ecf20Sopenharmony_ci state->ext_core_isr.reg_u32[vcpu_id][reg_count] &= ~val_data_u32; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci bits = sizeof(val_data_u32) * 8; 4938c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u32, bits); 4948c2ecf20Sopenharmony_ci while (i < bits) { 4958c2ecf20Sopenharmony_ci ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 4968c2ecf20Sopenharmony_ci bitmap_clear((void *)&val_data_u32, i, 1); 4978c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u32, bits); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 5008c2ecf20Sopenharmony_ci tmp_data_u8 = val_data_u32 & 0xff; 5018c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 5028c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 8) & 0xff; 5038c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 5048c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 16) & 0xff; 5058c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 5068c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 24) & 0xff; 5078c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 5088c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 5098c2ecf20Sopenharmony_ci tmp_data_u8 = val_data_u32 & 0xff; 5108c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 5118c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 8) & 0xff; 5128c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 5138c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 16) & 0xff; 5148c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 5158c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u32 >> 24) & 0xff; 5168c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 5178c2ecf20Sopenharmony_ci kvm_debug("%s:id:%d addr=0x%llx, offset 0x%llx val 0x%x\n", 5188c2ecf20Sopenharmony_ci __FUNCTION__, vcpu->vcpu_id, addr, offset, val_data_u32); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 5218c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START) / 4; 5228c2ecf20Sopenharmony_ci state->node_type.reg_u32[reg_count] = val_data_u32; 5238c2ecf20Sopenharmony_ci } else { 5248c2ecf20Sopenharmony_ci WARN_ONCE(1, "%s:%d Abnormal address access:addr 0x%llx\n", 5258c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, addr); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_writel(struct kvm_vcpu *vcpu, 5328c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 5338c2ecf20Sopenharmony_ci gpa_t addr, const void *__val) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci uint64_t offset, val_data_u64, old_data_u64, reg_count, mask, i; 5368c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 5378c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *state = NULL; 5388c2ecf20Sopenharmony_ci struct kvm *kvm = NULL; 5398c2ecf20Sopenharmony_ci uint8_t tmp_data_u8; 5408c2ecf20Sopenharmony_ci int level, vcpu_id; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci unsigned long val = *(unsigned long *)__val; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci state = &(s->ls3a_ext_irq); 5478c2ecf20Sopenharmony_ci kvm = s->kvm; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 5508c2ecf20Sopenharmony_ci val_data_u64 = val; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci kvm_debug("%s: addr=0x%llx,val=0x%lx\n", __FUNCTION__, addr, val); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if ((offset >= EXTIOI_ENABLE_START) && (offset < EXTIOI_ENABLE_END)) { 5558c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ENABLE_START) / 8; 5568c2ecf20Sopenharmony_ci old_data_u64 = state->ext_en.reg_u64[reg_count]; 5578c2ecf20Sopenharmony_ci if (old_data_u64 != val_data_u64) { 5588c2ecf20Sopenharmony_ci state->ext_en.reg_u64[reg_count] = val_data_u64; 5598c2ecf20Sopenharmony_ci old_data_u64 = old_data_u64 ^ val_data_u64; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci mask = 0x1; 5628c2ecf20Sopenharmony_ci for (i = 0; i < 8 * sizeof(old_data_u64); i++) { 5638c2ecf20Sopenharmony_ci if (old_data_u64 & mask) { 5648c2ecf20Sopenharmony_ci level = !!(val_data_u64 & (0x1 << i)); 5658c2ecf20Sopenharmony_ci if (level) 5668c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 64, level); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci mask = mask << 1; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_BOUNCE_START) && (offset < EXTIOI_BOUNCE_END)) { 5728c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_BOUNCE_START) / 8; 5738c2ecf20Sopenharmony_ci state->bounce.reg_u64[reg_count] = val_data_u64; 5748c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_ISR_START) && (offset < EXTIOI_ISR_END)) { 5758c2ecf20Sopenharmony_ci /*can not be writen*/ 5768c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_ISR_START) / 8; 5778c2ecf20Sopenharmony_ci old_data_u64 = state->ext_isr.reg_u64[reg_count]; 5788c2ecf20Sopenharmony_ci state->ext_isr.reg_u64[reg_count] = old_data_u64 & (~val_data_u64); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mask = 0x1; 5818c2ecf20Sopenharmony_ci for (i = 0; i < 8 * sizeof(old_data_u64); i++) { 5828c2ecf20Sopenharmony_ci if ((old_data_u64 & mask) && (val_data_u64 & mask)) { 5838c2ecf20Sopenharmony_ci ext_irq_update_core(kvm, i + reg_count * 64, 0); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci mask = mask << 1; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREISR_START) && (offset < EXTIOI_COREISR_END)) { 5888c2ecf20Sopenharmony_ci int bits; 5898c2ecf20Sopenharmony_ci vcpu_id = (offset >> 8) & 0xff; 5908c2ecf20Sopenharmony_ci reg_count = (offset & 0x1f) / 8; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /*core_ext_ioisr*/ 5938c2ecf20Sopenharmony_ci state->ext_core_isr.reg_u64[vcpu_id][reg_count] &= ~val_data_u64; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci bits = sizeof(val_data_u64) * 8; 5968c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u64, bits); 5978c2ecf20Sopenharmony_ci while (i < bits) { 5988c2ecf20Sopenharmony_ci ext_deactive_core_isr(kvm, i + reg_count * bits, vcpu_id); 5998c2ecf20Sopenharmony_ci bitmap_clear((void *)&val_data_u64, i, 1); 6008c2ecf20Sopenharmony_ci i = find_first_bit((void *)&val_data_u64, bits); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_IPMAP_START) && (offset < EXTIOI_IPMAP_END)) { 6038c2ecf20Sopenharmony_ci tmp_data_u8 = val_data_u64 & 0xff; 6048c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 6058c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 8) & 0xff; 6068c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 6078c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 16) & 0xff; 6088c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 6098c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 24) & 0xff; 6108c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 32) & 0xff; 6138c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 4, &tmp_data_u8); 6148c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 40) & 0xff; 6158c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 5, &tmp_data_u8); 6168c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 48) & 0xff; 6178c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 6, &tmp_data_u8); 6188c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 56) & 0xff; 6198c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 7, &tmp_data_u8); 6208c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_COREMAP_START) && (offset < EXTIOI_COREMAP_END)) { 6218c2ecf20Sopenharmony_ci tmp_data_u8 = val_data_u64 & 0xff; 6228c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr, &tmp_data_u8); 6238c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 8) & 0xff; 6248c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 1, &tmp_data_u8); 6258c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 16) & 0xff; 6268c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 2, &tmp_data_u8); 6278c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 24) & 0xff; 6288c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 3, &tmp_data_u8); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 32) & 0xff; 6318c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 4, &tmp_data_u8); 6328c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 40) & 0xff; 6338c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 5, &tmp_data_u8); 6348c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 48) & 0xff; 6358c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 6, &tmp_data_u8); 6368c2ecf20Sopenharmony_ci tmp_data_u8 = (val_data_u64 >> 56) & 0xff; 6378c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr + 7, &tmp_data_u8); 6388c2ecf20Sopenharmony_ci } else if ((offset >= EXTIOI_NODETYPE_START) && (offset < EXTIOI_NODETYPE_END)) { 6398c2ecf20Sopenharmony_ci reg_count = (offset - EXTIOI_NODETYPE_START) / 8; 6408c2ecf20Sopenharmony_ci state->node_type.reg_u64[reg_count] = val_data_u64; 6418c2ecf20Sopenharmony_ci } else { 6428c2ecf20Sopenharmony_ci WARN_ONCE(1, "%s:%d Abnormal address access:addr 0x%llx\n", 6438c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, addr); 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci/** 6488c2ecf20Sopenharmony_ci * ls3a_ext_intctl_write() 6498c2ecf20Sopenharmony_ci * @kvm: KVM structure pointer 6508c2ecf20Sopenharmony_ci * @addr: Register address 6518c2ecf20Sopenharmony_ci * @size: The width of the register to be writen. 6528c2ecf20Sopenharmony_ci * @val: Value to be written. 6538c2ecf20Sopenharmony_ci * 6548c2ecf20Sopenharmony_ci * Analog extended interrupt related register write. 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_cistatic int ls3a_ext_intctl_write(struct kvm_vcpu *vcpu, 6588c2ecf20Sopenharmony_ci struct kvm_io_device *dev, 6598c2ecf20Sopenharmony_ci gpa_t addr, int size, const void *__val) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = NULL; 6628c2ecf20Sopenharmony_ci unsigned long flags; 6638c2ecf20Sopenharmony_ci uint64_t offset; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci s = container_of(dev, struct ls3a_kvm_extirq, device); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci offset = addr & 0xfffff; 6688c2ecf20Sopenharmony_ci if (offset & (size - 1)) { 6698c2ecf20Sopenharmony_ci printk("%s(%d):unaligned address access %llx size %d\n", 6708c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, addr, size); 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci addr = (addr & 0xfffff) - EXTIOI_ADDR_OFF; 6758c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(s, flags); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci switch (size) { 6788c2ecf20Sopenharmony_ci case 1: 6798c2ecf20Sopenharmony_ci ls3a_ext_intctl_writeb(vcpu, dev, addr, __val); 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci case 4: 6828c2ecf20Sopenharmony_ci ls3a_ext_intctl_writew(vcpu, dev, addr, __val); 6838c2ecf20Sopenharmony_ci break; 6848c2ecf20Sopenharmony_ci case 8: 6858c2ecf20Sopenharmony_ci ls3a_ext_intctl_writel(vcpu, dev, addr, __val); 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci default: 6888c2ecf20Sopenharmony_ci WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx,size %d\n", 6898c2ecf20Sopenharmony_ci __FUNCTION__, addr, size); 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(s, flags); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci kvm_debug("%s(%d):address access %llx size %d\n", 6958c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, offset, size); 6968c2ecf20Sopenharmony_ci return 0; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic const struct kvm_io_device_ops kvm_ls3a_ext_irq_ops = { 7008c2ecf20Sopenharmony_ci .read = ls3a_ext_intctl_read, 7018c2ecf20Sopenharmony_ci .write = ls3a_ext_intctl_write, 7028c2ecf20Sopenharmony_ci}; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_civoid kvm_destroy_ls3a_ext_irq(struct kvm *kvm) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s = kvm->arch.v_extirq; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (!s) 7098c2ecf20Sopenharmony_ci return; 7108c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 7118c2ecf20Sopenharmony_ci kvm_io_bus_unregister_dev(s->kvm, KVM_MMIO_BUS, &s->device); 7128c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 7138c2ecf20Sopenharmony_ci kfree(s); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci/* 7168c2ecf20Sopenharmony_ci * kvm_create_ls3a_ext_irq() 7178c2ecf20Sopenharmony_ci * @kvm KVM structure pointer 7188c2ecf20Sopenharmony_ci * Create an extended interrupt resource instance for a virtual machine 7198c2ecf20Sopenharmony_ci * Returns: Extended interrupt structure pointer 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ciint kvm_create_ls3a_ext_irq(struct kvm *kvm) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *s; 7248c2ecf20Sopenharmony_ci int ret; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci s = kzalloc(sizeof(struct ls3a_kvm_extirq), GFP_KERNEL); 7278c2ecf20Sopenharmony_ci if (!s) 7288c2ecf20Sopenharmony_ci return -ENOMEM; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci memset((void *)&s->ls3a_ext_irq, 0x0, sizeof(struct kvm_ls3a_extirq_state)); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci spin_lock_init(&s->lock); 7338c2ecf20Sopenharmony_ci s->kvm = kvm; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * Initialize MMIO device 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci kvm_iodevice_init(&s->device, &kvm_ls3a_ext_irq_ops); 7398c2ecf20Sopenharmony_ci mutex_lock(&kvm->slots_lock); 7408c2ecf20Sopenharmony_ci ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, 7418c2ecf20Sopenharmony_ci EXTIOI_REG_BASE, EXTIOI_ADDR_SIZE, &s->device); 7428c2ecf20Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 7438c2ecf20Sopenharmony_ci if (ret < 0) { 7448c2ecf20Sopenharmony_ci printk("%s dev_ls3a_ext_irq register error ret %d\n", __FUNCTION__, ret); 7458c2ecf20Sopenharmony_ci goto err_register; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci kvm->arch.v_extirq = s; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cierr_register: 7538c2ecf20Sopenharmony_ci kfree(s); 7548c2ecf20Sopenharmony_ci return -EFAULT; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int kvm_set_ext_sw_ipmap(struct kvm_ls3a_extirq_state *state) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci uint8_t val_data_u8; 7608c2ecf20Sopenharmony_ci int i, j, base_irq, irqnum, ipnum; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci ipnum = 0; 7638c2ecf20Sopenharmony_ci for (i = 0; i < EXTIOI_IRQS_IPMAP_SIZE; i++) { 7648c2ecf20Sopenharmony_ci val_data_u8 = state->ip_map.reg_u8[i]; 7658c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 7668c2ecf20Sopenharmony_ci if (val_data_u8 & (0x1 << j)) { 7678c2ecf20Sopenharmony_ci ipnum = j; 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci kvm_debug("%s:%d ipnum:%d i:%d val_data_u8:0x%x\n", __FUNCTION__, __LINE__, 7728c2ecf20Sopenharmony_ci ipnum, i, val_data_u8); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (val_data_u8) { 7758c2ecf20Sopenharmony_ci for (base_irq = 0; base_irq < EXTIOI_IRQS_PER_GROUP; base_irq++) { 7768c2ecf20Sopenharmony_ci irqnum = i * EXTIOI_IRQS_PER_GROUP + base_irq; 7778c2ecf20Sopenharmony_ci state->ext_sw_ipmap[irqnum] = ipnum; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci for (base_irq = 0; base_irq < EXTIOI_IRQS_PER_GROUP; base_irq++) { 7818c2ecf20Sopenharmony_ci irqnum = i * EXTIOI_IRQS_PER_GROUP + base_irq; 7828c2ecf20Sopenharmony_ci state->ext_sw_ipmap[irqnum] = 0; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int kvm_set_ext_sw_coremap(struct kvm *kvm, struct kvm_ls3a_extirq_state *state) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci int reg_count; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci for (reg_count = 0; reg_count < EXTIOI_IRQS; reg_count++) { 7958c2ecf20Sopenharmony_ci state->ext_sw_coremap[reg_count] = state->core_map.reg_u8[reg_count]; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci kvm_debug("%s:%d -- reg_count:%d vcpu %d\n", 7988c2ecf20Sopenharmony_ci __FUNCTION__, __LINE__, reg_count, state->core_map.reg_u8[reg_count]); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic int kvm_set_ext_sw_ipisr(struct kvm *kvm, struct kvm_ls3a_extirq_state *state) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci int ipnum, core, irq_num; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci for (irq_num = 0; irq_num < EXTIOI_IRQS; irq_num++) { 8098c2ecf20Sopenharmony_ci core = state->ext_sw_coremap[irq_num]; 8108c2ecf20Sopenharmony_ci ipnum = state->ext_sw_ipmap[irq_num]; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (test_bit(irq_num, (void *)state->ext_core_isr.reg_u8[core]) == false) { 8138c2ecf20Sopenharmony_ci bitmap_clear((void *)state->ext_sw_ipisr[core][ipnum + 2], irq_num, 1); 8148c2ecf20Sopenharmony_ci } else { 8158c2ecf20Sopenharmony_ci bitmap_set((void *)state->ext_sw_ipisr[core][ipnum + 2], irq_num, 1); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ciint kvm_get_ls3a_extirq(struct kvm *kvm, struct kvm_loongarch_ls3a_extirq_state *state) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 8258c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 8268c2ecf20Sopenharmony_ci unsigned long flags; 8278c2ecf20Sopenharmony_ci if (!v_extirq) 8288c2ecf20Sopenharmony_ci return -EINVAL; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(v_extirq, flags); 8318c2ecf20Sopenharmony_ci memcpy(state, extirq_state, 8328c2ecf20Sopenharmony_ci sizeof(struct kvm_loongarch_ls3a_extirq_state)); 8338c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(v_extirq, flags); 8348c2ecf20Sopenharmony_ci kvm->stat.get_ls3a_ext_irq++; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciint kvm_set_ls3a_extirq(struct kvm *kvm, struct kvm_loongarch_ls3a_extirq_state *state) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 8428c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 8438c2ecf20Sopenharmony_ci unsigned long flags; 8448c2ecf20Sopenharmony_ci if (!v_extirq) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(v_extirq, flags); 8488c2ecf20Sopenharmony_ci memcpy(extirq_state, state, 8498c2ecf20Sopenharmony_ci sizeof(struct kvm_loongarch_ls3a_extirq_state)); 8508c2ecf20Sopenharmony_ci kvm_set_ext_sw_ipmap(extirq_state); 8518c2ecf20Sopenharmony_ci kvm_set_ext_sw_coremap(kvm, extirq_state); 8528c2ecf20Sopenharmony_ci kvm_set_ext_sw_ipisr(kvm, extirq_state); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(v_extirq, flags); 8558c2ecf20Sopenharmony_ci kvm->stat.set_ls3a_ext_irq++; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ciint kvm_setup_ls3a_extirq(struct kvm *kvm) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *v_extirq = ls3a_ext_irqchip(kvm); 8638c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *extirq_state = &(v_extirq->ls3a_ext_irq); 8648c2ecf20Sopenharmony_ci unsigned long flags; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (!v_extirq) 8678c2ecf20Sopenharmony_ci return -EINVAL; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(v_extirq, flags); 8708c2ecf20Sopenharmony_ci memset(extirq_state, 0, sizeof(struct kvm_ls3a_extirq_state)); 8718c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(v_extirq, flags); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return 0; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_civoid kvm_dump_ls3a_extirq_state(struct seq_file *s, 8778c2ecf20Sopenharmony_ci struct ls3a_kvm_extirq *irqchip) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct kvm_ls3a_extirq_state *extirq; 8808c2ecf20Sopenharmony_ci int i, j = 0; 8818c2ecf20Sopenharmony_ci unsigned long flags; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci seq_puts(s, "LS3A ext irqchip state:\n"); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!irqchip) 8868c2ecf20Sopenharmony_ci return; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci extirq = &(irqchip->ls3a_ext_irq); 8898c2ecf20Sopenharmony_ci ls3a_ext_irq_lock(irqchip, flags); 8908c2ecf20Sopenharmony_ci seq_puts(s, "ext irq enabled"); 8918c2ecf20Sopenharmony_ci seq_puts(s, "\nenabled:(Not Enabled)"); 8928c2ecf20Sopenharmony_ci for (i = 0; i < EXTIOI_IRQS; i++) { 8938c2ecf20Sopenharmony_ci if (!test_bit(i, (void *)&extirq->ext_en)) 8948c2ecf20Sopenharmony_ci seq_printf(s, "%d ", i); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci seq_puts(s, "\nbounce:(Not bounce)"); 8978c2ecf20Sopenharmony_ci for (i = 0; i < EXTIOI_IRQS; i++) { 8988c2ecf20Sopenharmony_ci if (!test_bit(i, (void *)&extirq->bounce)) 8998c2ecf20Sopenharmony_ci seq_printf(s, "%d ", i); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci seq_puts(s, "\next_isr:"); 9028c2ecf20Sopenharmony_ci for (i = 0; i < EXTIOI_IRQS; i++) { 9038c2ecf20Sopenharmony_ci if (test_bit(i, (void *)&extirq->ext_isr)) 9048c2ecf20Sopenharmony_ci seq_printf(s, "%d ", i); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci seq_puts(s, "\ncore_isr:"); 9088c2ecf20Sopenharmony_ci for (i = 0; i < KVM_MAX_VCPUS && kvm_get_vcpu_by_id(irqchip->kvm, i); i++) { 9098c2ecf20Sopenharmony_ci seq_printf(s, "\n\t CPU%d:", i); 9108c2ecf20Sopenharmony_ci for (j = 0; j < EXTIOI_IRQS; j++) { 9118c2ecf20Sopenharmony_ci if (test_bit(j, (void *)&extirq->ext_core_isr.reg_u8[i])) 9128c2ecf20Sopenharmony_ci seq_printf(s, "%d ", j); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci seq_printf(s, "\nip_map:%llx", extirq->ip_map.reg_u64); 9168c2ecf20Sopenharmony_ci seq_puts(s, "\ncore_map: (only display router to slave cpu)\n"); 9178c2ecf20Sopenharmony_ci for (i = 0; i < EXTIOI_IRQS_COREMAP_SIZE; i++) 9188c2ecf20Sopenharmony_ci if (extirq->core_map.reg_u8[i]) 9198c2ecf20Sopenharmony_ci seq_printf(s, "\tirq:%d -> cpu:%d\n", i, 9208c2ecf20Sopenharmony_ci extirq->core_map.reg_u8[i]); 9218c2ecf20Sopenharmony_ci ls3a_ext_irq_unlock(irqchip, flags); 9228c2ecf20Sopenharmony_ci} 923