xref: /openbmc/qemu/hw/intc/loongarch_extioi_kvm.c (revision 228c5413fb50ab43644689f4959c3ef1ef7571ea)
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 
15*228c5413SBibo Mao static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
16*228c5413SBibo Mao {
17*228c5413SBibo Mao     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
18*228c5413SBibo Mao                       addr, val, write, &error_abort);
19*228c5413SBibo Mao }
20*228c5413SBibo Mao 
21*228c5413SBibo Mao static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
22*228c5413SBibo Mao                                        void *val, bool write)
23*228c5413SBibo Mao {
24*228c5413SBibo Mao     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
25*228c5413SBibo Mao                       addr, val, write, &error_abort);
26*228c5413SBibo Mao }
27*228c5413SBibo Mao 
28*228c5413SBibo Mao static void kvm_extioi_access_sw_status(void *opaque, bool write)
29*228c5413SBibo Mao {
30*228c5413SBibo Mao     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
31*228c5413SBibo Mao     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
32*228c5413SBibo Mao     int addr;
33*228c5413SBibo Mao 
34*228c5413SBibo Mao     addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
35*228c5413SBibo Mao     kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
36*228c5413SBibo Mao }
37*228c5413SBibo Mao 
38*228c5413SBibo Mao static void kvm_extioi_access_regs(void *opaque, bool write)
39*228c5413SBibo Mao {
40*228c5413SBibo Mao     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
41*228c5413SBibo Mao     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
42*228c5413SBibo Mao     int fd = les->dev_fd;
43*228c5413SBibo Mao     int addr, offset, cpu;
44*228c5413SBibo Mao 
45*228c5413SBibo Mao     for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
46*228c5413SBibo Mao         offset = (addr - EXTIOI_NODETYPE_START) / 4;
47*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
48*228c5413SBibo Mao     }
49*228c5413SBibo Mao 
50*228c5413SBibo Mao     for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
51*228c5413SBibo Mao         offset = (addr - EXTIOI_IPMAP_START) / 4;
52*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
53*228c5413SBibo Mao     }
54*228c5413SBibo Mao 
55*228c5413SBibo Mao     for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
56*228c5413SBibo Mao         offset = (addr - EXTIOI_ENABLE_START) / 4;
57*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
58*228c5413SBibo Mao     }
59*228c5413SBibo Mao 
60*228c5413SBibo Mao     for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
61*228c5413SBibo Mao         offset = (addr - EXTIOI_BOUNCE_START) / 4;
62*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
63*228c5413SBibo Mao     }
64*228c5413SBibo Mao 
65*228c5413SBibo Mao     for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
66*228c5413SBibo Mao         offset = (addr - EXTIOI_ISR_START) / 4;
67*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
68*228c5413SBibo Mao     }
69*228c5413SBibo Mao 
70*228c5413SBibo Mao     for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
71*228c5413SBibo Mao         offset = (addr - EXTIOI_COREMAP_START) / 4;
72*228c5413SBibo Mao         kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
73*228c5413SBibo Mao     }
74*228c5413SBibo Mao 
75*228c5413SBibo Mao     for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
76*228c5413SBibo Mao         for (addr = EXTIOI_COREISR_START;
77*228c5413SBibo Mao              addr < EXTIOI_COREISR_END; addr += 4) {
78*228c5413SBibo Mao             offset = (addr - EXTIOI_COREISR_START) / 4;
79*228c5413SBibo Mao             kvm_extioi_access_reg(fd, (cpu << 16) | addr,
80*228c5413SBibo Mao                                   &lecs->cpu[cpu].coreisr[offset], write);
81*228c5413SBibo Mao         }
82*228c5413SBibo Mao     }
83*228c5413SBibo Mao }
84*228c5413SBibo Mao 
85*228c5413SBibo Mao int kvm_extioi_get(void *opaque)
86*228c5413SBibo Mao {
87*228c5413SBibo Mao     kvm_extioi_access_regs(opaque, false);
88*228c5413SBibo Mao     kvm_extioi_access_sw_status(opaque, false);
89*228c5413SBibo Mao     return 0;
90*228c5413SBibo Mao }
91*228c5413SBibo Mao 
92*228c5413SBibo Mao int kvm_extioi_put(void *opaque, int version_id)
93*228c5413SBibo Mao {
94*228c5413SBibo Mao     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
95*228c5413SBibo Mao     int fd = les->dev_fd;
96*228c5413SBibo Mao 
97*228c5413SBibo Mao     kvm_extioi_access_regs(opaque, true);
98*228c5413SBibo Mao     kvm_extioi_access_sw_status(opaque, true);
99*228c5413SBibo Mao     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
100*228c5413SBibo Mao                       KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
101*228c5413SBibo Mao                       NULL, true, &error_abort);
102*228c5413SBibo Mao     return 0;
103*228c5413SBibo Mao }
104*228c5413SBibo Mao 
1058bf8814aSBibo Mao void kvm_extioi_realize(DeviceState *dev, Error **errp)
1068bf8814aSBibo Mao {
1078bf8814aSBibo Mao     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
1088bf8814aSBibo Mao     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
1098bf8814aSBibo Mao     int ret;
1108bf8814aSBibo Mao 
1118bf8814aSBibo Mao     ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
1128bf8814aSBibo Mao     if (ret < 0) {
1138bf8814aSBibo Mao         fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
1148bf8814aSBibo Mao                 strerror(-ret));
1158bf8814aSBibo Mao         abort();
1168bf8814aSBibo Mao     }
1178bf8814aSBibo Mao 
1188bf8814aSBibo Mao     les->dev_fd = ret;
1198bf8814aSBibo Mao     ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
1208bf8814aSBibo Mao                             KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
1218bf8814aSBibo Mao                             &lecs->num_cpu, true, NULL);
1228bf8814aSBibo Mao     if (ret < 0) {
1238bf8814aSBibo Mao         fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
1248bf8814aSBibo Mao                 strerror(-ret));
1258bf8814aSBibo Mao         abort();
1268bf8814aSBibo Mao     }
1278bf8814aSBibo Mao 
1288bf8814aSBibo Mao     ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
1298bf8814aSBibo Mao                             KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
1308bf8814aSBibo Mao                             &lecs->features, true, NULL);
1318bf8814aSBibo Mao     if (ret < 0) {
1328bf8814aSBibo Mao         fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
1338bf8814aSBibo Mao                 strerror(-ret));
1348bf8814aSBibo Mao         abort();
1358bf8814aSBibo Mao     }
1368bf8814aSBibo Mao }
137