1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * LoongArch ipi interrupt support
5 * Copyright (C) 2021 Loongson Technology Corporation Limited
8 #include "qemu/osdep.h"
10 #include "hw/intc/loongarch_ipi.h"
12 #include "qapi/error.h"
14 #include "exec/address-spaces.h"
15 #include "hw/loongarch/virt.h"
16 #include "migration/vmstate.h"
17 #include "target/loongarch/internals.h"
20 static uint64_t loongarch_ipi_readl(void *opaque
, hwaddr addr
, unsigned size
)
40 case CORE_BUF_20
... CORE_BUF_38
+ 4:
41 index
= (addr
- CORE_BUF_20
) >> 2;
45 qemu_log_mask(LOG_UNIMP
, "invalid read: %x", (uint32_t)addr
);
49 trace_loongarch_ipi_read(size
, (uint64_t)addr
, 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);
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
)
81 CPULoongArchState
*env
;
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
);
91 address_space_stl(&env
->address_space_iocsr
, 0x1008,
92 data
, MEMTXATTRS_UNSPECIFIED
, NULL
);
96 static void mail_send(uint64_t val
)
100 CPULoongArchState
*env
;
104 cpuid
= (val
>> 16) & 0x3ff;
105 addr
= 0x1020 + (val
& 0x1c);
106 cs
= qemu_get_cpu(cpuid
);
107 cpu
= LOONGARCH_CPU(cs
);
109 send_ipi_data(env
, val
, addr
);
112 static void any_send(uint64_t val
)
116 CPULoongArchState
*env
;
118 cpuid
= (val
>> 16) & 0x3ff;
120 CPUState
*cs
= qemu_get_cpu(cpuid
);
121 LoongArchCPU
*cpu
= LOONGARCH_CPU(cs
);
123 send_ipi_data(env
, val
, addr
);
126 static void loongarch_ipi_writel(void *opaque
, hwaddr addr
, uint64_t val
,
133 trace_loongarch_ipi_write(size
, (uint64_t)addr
, val
);
135 case CORE_STATUS_OFF
:
136 qemu_log_mask(LOG_GUEST_ERROR
, "can not be written");
143 if (s
->status
!= 0 && (s
->status
& s
->en
) != 0) {
144 qemu_irq_raise(s
->irq
);
149 if (s
->status
== 0 && s
->en
!= 0) {
150 qemu_irq_lower(s
->irq
);
153 case CORE_BUF_20
... CORE_BUF_38
+ 4:
154 index
= (addr
- CORE_BUF_20
) >> 2;
161 qemu_log_mask(LOG_UNIMP
, "invalid write: %x", (uint32_t)addr
);
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
,
182 case MAIL_SEND_OFFSET
:
185 case ANY_SEND_OFFSET
:
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
)
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")) {
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",
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
,
244 .minimum_version_id
= 0,
245 .fields
= (VMStateField
[]) {
246 VMSTATE_STRUCT_ARRAY(ipi_core
, LoongArchMachineState
,
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
)