qcow2: manually add more coroutine_fn annotations
[qemu.git] / hw / intc / loongarch_ipi.c
blobaa4bf9eb747bc4bc937d0ec72e1775f70963fd70
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * LoongArch ipi interrupt support
5 * Copyright (C) 2021 Loongson Technology Corporation Limited
6 */
8 #include "qemu/osdep.h"
9 #include "hw/sysbus.h"
10 #include "hw/intc/loongarch_ipi.h"
11 #include "hw/irq.h"
12 #include "qapi/error.h"
13 #include "qemu/log.h"
14 #include "exec/address-spaces.h"
15 #include "hw/loongarch/virt.h"
16 #include "migration/vmstate.h"
17 #include "target/loongarch/internals.h"
18 #include "trace.h"
20 static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
22 IPICore *s = opaque;
23 uint64_t ret = 0;
24 int index = 0;
26 addr &= 0xff;
27 switch (addr) {
28 case CORE_STATUS_OFF:
29 ret = s->status;
30 break;
31 case CORE_EN_OFF:
32 ret = s->en;
33 break;
34 case CORE_SET_OFF:
35 ret = 0;
36 break;
37 case CORE_CLEAR_OFF:
38 ret = 0;
39 break;
40 case CORE_BUF_20 ... CORE_BUF_38 + 4:
41 index = (addr - CORE_BUF_20) >> 2;
42 ret = s->buf[index];
43 break;
44 default:
45 qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
46 break;
49 trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
50 return ret;
53 static void send_ipi_data(CPULoongArchState *env, target_ulong val, target_ulong addr)
55 int i, mask = 0, data = 0;
58 * bit 27-30 is mask for byte writing,
59 * if the mask is 0, we need not to do anything.
61 if ((val >> 27) & 0xf) {
62 data = address_space_ldl(&env->address_space_iocsr, addr,
63 MEMTXATTRS_UNSPECIFIED, NULL);
64 for (i = 0; i < 4; i++) {
65 /* get mask for byte writing */
66 if (val & (0x1 << (27 + i))) {
67 mask |= 0xff << (i * 8);
72 data &= mask;
73 data |= (val >> 32) & ~mask;
74 address_space_stl(&env->address_space_iocsr, addr,
75 data, MEMTXATTRS_UNSPECIFIED, NULL);
78 static void ipi_send(uint64_t val)
80 int cpuid, data;
81 CPULoongArchState *env;
82 CPUState *cs;
83 LoongArchCPU *cpu;
85 cpuid = (val >> 16) & 0x3ff;
86 /* IPI status vector */
87 data = 1 << (val & 0x1f);
88 cs = qemu_get_cpu(cpuid);
89 cpu = LOONGARCH_CPU(cs);
90 env = &cpu->env;
91 address_space_stl(&env->address_space_iocsr, 0x1008,
92 data, MEMTXATTRS_UNSPECIFIED, NULL);
96 static void mail_send(uint64_t val)
98 int cpuid;
99 hwaddr addr;
100 CPULoongArchState *env;
101 CPUState *cs;
102 LoongArchCPU *cpu;
104 cpuid = (val >> 16) & 0x3ff;
105 addr = 0x1020 + (val & 0x1c);
106 cs = qemu_get_cpu(cpuid);
107 cpu = LOONGARCH_CPU(cs);
108 env = &cpu->env;
109 send_ipi_data(env, val, addr);
112 static void any_send(uint64_t val)
114 int cpuid;
115 hwaddr addr;
116 CPULoongArchState *env;
118 cpuid = (val >> 16) & 0x3ff;
119 addr = val & 0xffff;
120 CPUState *cs = qemu_get_cpu(cpuid);
121 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
122 env = &cpu->env;
123 send_ipi_data(env, val, addr);
126 static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
127 unsigned size)
129 IPICore *s = opaque;
130 int index = 0;
132 addr &= 0xff;
133 trace_loongarch_ipi_write(size, (uint64_t)addr, val);
134 switch (addr) {
135 case CORE_STATUS_OFF:
136 qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
137 break;
138 case CORE_EN_OFF:
139 s->en = val;
140 break;
141 case CORE_SET_OFF:
142 s->status |= val;
143 if (s->status != 0 && (s->status & s->en) != 0) {
144 qemu_irq_raise(s->irq);
146 break;
147 case CORE_CLEAR_OFF:
148 s->status &= ~val;
149 if (s->status == 0 && s->en != 0) {
150 qemu_irq_lower(s->irq);
152 break;
153 case CORE_BUF_20 ... CORE_BUF_38 + 4:
154 index = (addr - CORE_BUF_20) >> 2;
155 s->buf[index] = val;
156 break;
157 case IOCSR_IPI_SEND:
158 ipi_send(val);
159 break;
160 default:
161 qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
162 break;
166 static const MemoryRegionOps loongarch_ipi_ops = {
167 .read = loongarch_ipi_readl,
168 .write = loongarch_ipi_writel,
169 .impl.min_access_size = 4,
170 .impl.max_access_size = 4,
171 .valid.min_access_size = 4,
172 .valid.max_access_size = 8,
173 .endianness = DEVICE_LITTLE_ENDIAN,
176 /* mail send and any send only support writeq */
177 static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
178 unsigned size)
180 addr &= 0xfff;
181 switch (addr) {
182 case MAIL_SEND_OFFSET:
183 mail_send(val);
184 break;
185 case ANY_SEND_OFFSET:
186 any_send(val);
187 break;
188 default:
189 break;
193 static const MemoryRegionOps loongarch_ipi64_ops = {
194 .write = loongarch_ipi_writeq,
195 .impl.min_access_size = 8,
196 .impl.max_access_size = 8,
197 .valid.min_access_size = 8,
198 .valid.max_access_size = 8,
199 .endianness = DEVICE_LITTLE_ENDIAN,
202 static void loongarch_ipi_init(Object *obj)
204 int cpu;
205 LoongArchMachineState *lams;
206 LoongArchIPI *s = LOONGARCH_IPI(obj);
207 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
208 Object *machine = qdev_get_machine();
209 ObjectClass *mc = object_get_class(machine);
210 /* 'lams' should be initialized */
211 if (!strcmp(MACHINE_CLASS(mc)->name, "none")) {
212 return;
214 lams = LOONGARCH_MACHINE(machine);
215 for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
216 memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops,
217 &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x48);
218 sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]);
220 memory_region_init_io(&s->ipi64_iocsr_mem[cpu], obj, &loongarch_ipi64_ops,
221 &lams->ipi_core[cpu], "loongarch_ipi64_iocsr", 0x118);
222 sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem[cpu]);
223 qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1);
227 static const VMStateDescription vmstate_ipi_core = {
228 .name = "ipi-single",
229 .version_id = 0,
230 .minimum_version_id = 0,
231 .fields = (VMStateField[]) {
232 VMSTATE_UINT32(status, IPICore),
233 VMSTATE_UINT32(en, IPICore),
234 VMSTATE_UINT32(set, IPICore),
235 VMSTATE_UINT32(clear, IPICore),
236 VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
237 VMSTATE_END_OF_LIST()
241 static const VMStateDescription vmstate_loongarch_ipi = {
242 .name = TYPE_LOONGARCH_IPI,
243 .version_id = 0,
244 .minimum_version_id = 0,
245 .fields = (VMStateField[]) {
246 VMSTATE_STRUCT_ARRAY(ipi_core, LoongArchMachineState,
247 MAX_IPI_CORE_NUM, 0,
248 vmstate_ipi_core, IPICore),
249 VMSTATE_END_OF_LIST()
253 static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
255 DeviceClass *dc = DEVICE_CLASS(klass);
257 dc->vmsd = &vmstate_loongarch_ipi;
260 static const TypeInfo loongarch_ipi_info = {
261 .name = TYPE_LOONGARCH_IPI,
262 .parent = TYPE_SYS_BUS_DEVICE,
263 .instance_size = sizeof(LoongArchIPI),
264 .instance_init = loongarch_ipi_init,
265 .class_init = loongarch_ipi_class_init,
268 static void loongarch_ipi_register_types(void)
270 type_register_static(&loongarch_ipi_info);
273 type_init(loongarch_ipi_register_types)