18bf8814aSBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */
28bf8814aSBibo Mao /*
38bf8814aSBibo Mao * LoongArch EXTIOI interrupt kvm support
48bf8814aSBibo Mao *
58bf8814aSBibo Mao * Copyright (C) 2025 Loongson Technology Corporation Limited
68bf8814aSBibo Mao */
78bf8814aSBibo Mao
88bf8814aSBibo Mao #include "qemu/osdep.h"
98bf8814aSBibo Mao #include "qemu/typedefs.h"
108bf8814aSBibo Mao #include "hw/intc/loongarch_extioi.h"
118bf8814aSBibo Mao #include "linux/kvm.h"
128bf8814aSBibo Mao #include "qapi/error.h"
138bf8814aSBibo Mao #include "system/kvm.h"
148bf8814aSBibo Mao
kvm_extioi_access_reg(int fd,uint64_t addr,void * val,bool write)15228c5413SBibo Mao static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
16228c5413SBibo Mao {
17228c5413SBibo Mao kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
18228c5413SBibo Mao addr, val, write, &error_abort);
19228c5413SBibo Mao }
20228c5413SBibo Mao
kvm_extioi_access_sw_state(int fd,uint64_t addr,void * val,bool write)21228c5413SBibo Mao static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
22228c5413SBibo Mao void *val, bool write)
23228c5413SBibo Mao {
24228c5413SBibo Mao kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
25228c5413SBibo Mao addr, val, write, &error_abort);
26228c5413SBibo Mao }
27228c5413SBibo Mao
kvm_extioi_access_sw_status(void * opaque,bool write)28228c5413SBibo Mao static void kvm_extioi_access_sw_status(void *opaque, bool write)
29228c5413SBibo Mao {
30228c5413SBibo Mao LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
31228c5413SBibo Mao LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
32228c5413SBibo Mao int addr;
33228c5413SBibo Mao
34228c5413SBibo Mao addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
35228c5413SBibo Mao kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
36228c5413SBibo Mao }
37228c5413SBibo Mao
kvm_extioi_access_regs(void * opaque,bool write)38228c5413SBibo Mao static void kvm_extioi_access_regs(void *opaque, bool write)
39228c5413SBibo Mao {
40228c5413SBibo Mao LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
41228c5413SBibo Mao LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
42228c5413SBibo Mao int fd = les->dev_fd;
43228c5413SBibo Mao int addr, offset, cpu;
44228c5413SBibo Mao
45228c5413SBibo Mao for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
46228c5413SBibo Mao offset = (addr - EXTIOI_NODETYPE_START) / 4;
47228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
48228c5413SBibo Mao }
49228c5413SBibo Mao
50228c5413SBibo Mao for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
51228c5413SBibo Mao offset = (addr - EXTIOI_IPMAP_START) / 4;
52228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
53228c5413SBibo Mao }
54228c5413SBibo Mao
55228c5413SBibo Mao for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
56228c5413SBibo Mao offset = (addr - EXTIOI_ENABLE_START) / 4;
57228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
58228c5413SBibo Mao }
59228c5413SBibo Mao
60228c5413SBibo Mao for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
61228c5413SBibo Mao offset = (addr - EXTIOI_BOUNCE_START) / 4;
62228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
63228c5413SBibo Mao }
64228c5413SBibo Mao
65228c5413SBibo Mao for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
66228c5413SBibo Mao offset = (addr - EXTIOI_ISR_START) / 4;
67228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
68228c5413SBibo Mao }
69228c5413SBibo Mao
70228c5413SBibo Mao for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
71228c5413SBibo Mao offset = (addr - EXTIOI_COREMAP_START) / 4;
72228c5413SBibo Mao kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
73228c5413SBibo Mao }
74228c5413SBibo Mao
75228c5413SBibo Mao for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
76228c5413SBibo Mao for (addr = EXTIOI_COREISR_START;
77228c5413SBibo Mao addr < EXTIOI_COREISR_END; addr += 4) {
78228c5413SBibo Mao offset = (addr - EXTIOI_COREISR_START) / 4;
79228c5413SBibo Mao kvm_extioi_access_reg(fd, (cpu << 16) | addr,
80228c5413SBibo Mao &lecs->cpu[cpu].coreisr[offset], write);
81228c5413SBibo Mao }
82228c5413SBibo Mao }
83228c5413SBibo Mao }
84228c5413SBibo Mao
kvm_extioi_get(void * opaque)85228c5413SBibo Mao int kvm_extioi_get(void *opaque)
86228c5413SBibo Mao {
87228c5413SBibo Mao kvm_extioi_access_regs(opaque, false);
88228c5413SBibo Mao kvm_extioi_access_sw_status(opaque, false);
89228c5413SBibo Mao return 0;
90228c5413SBibo Mao }
91228c5413SBibo Mao
kvm_extioi_put(void * opaque,int version_id)92228c5413SBibo Mao int kvm_extioi_put(void *opaque, int version_id)
93228c5413SBibo Mao {
94228c5413SBibo Mao LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
95228c5413SBibo Mao int fd = les->dev_fd;
96228c5413SBibo Mao
97*c642ddf1SBibo Mao if (fd == 0) {
98*c642ddf1SBibo Mao return 0;
99*c642ddf1SBibo Mao }
100*c642ddf1SBibo Mao
101228c5413SBibo Mao kvm_extioi_access_regs(opaque, true);
102228c5413SBibo Mao kvm_extioi_access_sw_status(opaque, true);
103228c5413SBibo Mao kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
104228c5413SBibo Mao KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
105228c5413SBibo Mao NULL, true, &error_abort);
106228c5413SBibo Mao return 0;
107228c5413SBibo Mao }
108228c5413SBibo Mao
kvm_extioi_realize(DeviceState * dev,Error ** errp)1098bf8814aSBibo Mao void kvm_extioi_realize(DeviceState *dev, Error **errp)
1108bf8814aSBibo Mao {
1118bf8814aSBibo Mao LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
1128bf8814aSBibo Mao LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
1138bf8814aSBibo Mao int ret;
1148bf8814aSBibo Mao
1158bf8814aSBibo Mao ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
1168bf8814aSBibo Mao if (ret < 0) {
1178bf8814aSBibo Mao fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
1188bf8814aSBibo Mao strerror(-ret));
1198bf8814aSBibo Mao abort();
1208bf8814aSBibo Mao }
1218bf8814aSBibo Mao
1228bf8814aSBibo Mao les->dev_fd = ret;
1238bf8814aSBibo Mao ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
1248bf8814aSBibo Mao KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
1258bf8814aSBibo Mao &lecs->num_cpu, true, NULL);
1268bf8814aSBibo Mao if (ret < 0) {
1278bf8814aSBibo Mao fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
1288bf8814aSBibo Mao strerror(-ret));
1298bf8814aSBibo Mao abort();
1308bf8814aSBibo Mao }
1318bf8814aSBibo Mao
1328bf8814aSBibo Mao ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
1338bf8814aSBibo Mao KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
1348bf8814aSBibo Mao &lecs->features, true, NULL);
1358bf8814aSBibo Mao if (ret < 0) {
1368bf8814aSBibo Mao fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
1378bf8814aSBibo Mao strerror(-ret));
1388bf8814aSBibo Mao abort();
1398bf8814aSBibo Mao }
1408bf8814aSBibo Mao }
141