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