xref: /openbmc/qemu/hw/intc/loongarch_extioi_kvm.c (revision a56ac09f5c37f57059c2a2c5ae6aeff7f7241a84)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * LoongArch EXTIOI interrupt kvm support
4  *
5  * Copyright (C) 2025 Loongson Technology Corporation Limited
6  */
7 
8 #include "qemu/osdep.h"
9 #include "hw/intc/loongarch_extioi.h"
10 #include "linux/kvm.h"
11 #include "qapi/error.h"
12 #include "system/kvm.h"
13 
kvm_extioi_access_reg(int fd,uint64_t addr,void * val,bool write)14 static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
15 {
16     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
17                       addr, val, write, &error_abort);
18 }
19 
kvm_extioi_access_sw_state(int fd,uint64_t addr,void * val,bool write)20 static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
21                                        void *val, bool write)
22 {
23     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
24                       addr, val, write, &error_abort);
25 }
26 
kvm_extioi_access_sw_status(void * opaque,bool write)27 static void kvm_extioi_access_sw_status(void *opaque, bool write)
28 {
29     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
30     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
31     int addr;
32 
33     addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
34     kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
35 }
36 
kvm_extioi_access_regs(void * opaque,bool write)37 static void kvm_extioi_access_regs(void *opaque, bool write)
38 {
39     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
40     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
41     int fd = les->dev_fd;
42     int addr, offset, cpu;
43 
44     for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
45         offset = (addr - EXTIOI_NODETYPE_START) / 4;
46         kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
47     }
48 
49     for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
50         offset = (addr - EXTIOI_IPMAP_START) / 4;
51         kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
52     }
53 
54     for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
55         offset = (addr - EXTIOI_ENABLE_START) / 4;
56         kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
57     }
58 
59     for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
60         offset = (addr - EXTIOI_BOUNCE_START) / 4;
61         kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
62     }
63 
64     for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
65         offset = (addr - EXTIOI_ISR_START) / 4;
66         kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
67     }
68 
69     for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
70         offset = (addr - EXTIOI_COREMAP_START) / 4;
71         kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
72     }
73 
74     for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
75         for (addr = EXTIOI_COREISR_START;
76              addr < EXTIOI_COREISR_END; addr += 4) {
77             offset = (addr - EXTIOI_COREISR_START) / 4;
78             kvm_extioi_access_reg(fd, (cpu << 16) | addr,
79                                   &lecs->cpu[cpu].coreisr[offset], write);
80         }
81     }
82 }
83 
kvm_extioi_get(void * opaque)84 int kvm_extioi_get(void *opaque)
85 {
86     kvm_extioi_access_regs(opaque, false);
87     kvm_extioi_access_sw_status(opaque, false);
88     return 0;
89 }
90 
kvm_extioi_put(void * opaque,int version_id)91 int kvm_extioi_put(void *opaque, int version_id)
92 {
93     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
94     int fd = les->dev_fd;
95 
96     if (fd == 0) {
97         return 0;
98     }
99 
100     kvm_extioi_access_regs(opaque, true);
101     kvm_extioi_access_sw_status(opaque, true);
102     kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
103                       KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
104                       NULL, true, &error_abort);
105     return 0;
106 }
107 
kvm_extioi_realize(DeviceState * dev,Error ** errp)108 void kvm_extioi_realize(DeviceState *dev, Error **errp)
109 {
110     LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
111     LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
112     int ret;
113 
114     ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
115     if (ret < 0) {
116         fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
117                 strerror(-ret));
118         abort();
119     }
120 
121     les->dev_fd = ret;
122     ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
123                             KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
124                             &lecs->num_cpu, true, NULL);
125     if (ret < 0) {
126         fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
127                 strerror(-ret));
128         abort();
129     }
130 
131     ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
132                             KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
133                             &lecs->features, true, NULL);
134     if (ret < 0) {
135         fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
136                 strerror(-ret));
137         abort();
138     }
139 }
140