new file mode 100644
@@ -0,0 +1,145 @@
+/*
+ * Loongarch ipi interrupt support
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "exec/address-spaces.h"
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
+#include "cpu.h"
+#include "qemu/log.h"
+#include "hw/loongarch/loongarch.h"
+#include "migration/vmstate.h"
+
+static const VMStateDescription vmstate_gipi_core = {
+ .name = "gipi-single",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, gipi_core),
+ VMSTATE_UINT32(en, gipi_core),
+ VMSTATE_UINT32(set, gipi_core),
+ VMSTATE_UINT32(clear, gipi_core),
+ VMSTATE_UINT64_ARRAY(buf, gipi_core, MAX_GIPI_MBX_NUM),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_gipi = {
+ .name = "gipi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(core, gipiState, MAX_GIPI_CORE_NUM, 0,
+ vmstate_gipi_core, gipi_core),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void gipi_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ gipi_core *s = opaque;
+ void *pbuf;
+
+ if (size != 4) {
+ hw_error("size not 4");
+ }
+ addr &= 0xff;
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ hw_error("CORE_SET_OFF Can't be write\n");
+ break;
+ case CORE_EN_OFF:
+ s->en = val;
+ break;
+ case CORE_SET_OFF:
+ s->status |= val;
+ if (s->status != 0) {
+ qemu_irq_raise(s->irq);
+ }
+ break;
+ case CORE_CLEAR_OFF:
+ s->status ^= val;
+ if (s->status == 0) {
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38:
+ pbuf = (void *)s->buf + (addr - 0x20);
+ *(unsigned int *)pbuf = val;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t gipi_readl(void *opaque, hwaddr addr, unsigned size)
+{
+ gipi_core *s = opaque;
+ uint64_t ret = 0;
+ void *pbuf;
+
+ addr &= 0xff;
+ if (size != 4) {
+ hw_error("size not 4 %d\n", size);
+ }
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ ret = s->status;
+ break;
+ case CORE_EN_OFF:
+ ret = s->en;
+ break;
+ case CORE_SET_OFF:
+ ret = 0;
+ break;
+ case CORE_CLEAR_OFF:
+ ret = 0;
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38:
+ pbuf = (void *)s->buf + (addr - 0x20);
+ ret = *(unsigned int *)pbuf;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static const MemoryRegionOps gipi_ops = {
+ .read = gipi_readl,
+ .write = gipi_writel,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+int cpu_init_ipi(LoongarchMachineState *lsms, qemu_irq parent, int cpu)
+{
+ int core_num = cpu % 4;
+ hwaddr addr;
+ MemoryRegion *region;
+ char str[32];
+
+ if (lsms->gipi == NULL) {
+ lsms->gipi = g_malloc0(sizeof(gipiState));
+ vmstate_register(NULL, 0, &vmstate_gipi, lsms->gipi);
+ }
+
+ lsms->gipi->core[cpu].irq = parent;
+
+ addr = SMP_GIPI_MAILBOX + core_num * 0x100;
+ region = g_new(MemoryRegion, 1);
+ sprintf(str, "gipi%d", cpu);
+ memory_region_init_io(region, NULL, &gipi_ops,
+ &lsms->gipi->core[cpu], str, 0x100);
+ memory_region_add_subregion(get_system_memory(), addr, region);
+ return 0;
+}
@@ -113,6 +113,7 @@ static void ls3a5000_virt_init(MachineState *machine)
char *ramName = NULL;
ram_addr_t ram_size = machine->ram_size;
MemoryRegion *address_space_mem = get_system_memory();
+ LoongarchMachineState *lsms = LOONGARCH_MACHINE(machine);
int i;
MemoryRegion *iomem = NULL;
@@ -148,6 +149,7 @@ static void ls3a5000_virt_init(MachineState *machine)
/* Init CPU internal devices */
cpu_loongarch_init_irq(cpu);
cpu_loongarch_clock_init(cpu);
+ cpu_init_ipi(lsms, env->irq[IRQ_IPI], i);
qemu_register_reset(main_cpu_reset, cpu);
}
@@ -1,5 +1,5 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(files('loongarch_int.c'))
-loongarch_ss.add(when: 'CONFIG_LOONGSON_3A5000', if_true: files('ls3a5000_virt.c'))
+loongarch_ss.add(when: 'CONFIG_LOONGSON_3A5000', if_true: files('ls3a5000_virt.c', 'ipi.c'))
hw_arch += {'loongarch': loongarch_ss}
new file mode 100644
@@ -0,0 +1,38 @@
+/*
+ * Loongarch ipi interrupt header files
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#ifndef HW_LOONGARCH_GIPI_H
+#define HW_LOONGARCH_GIPI_H
+
+#define SMP_GIPI_MAILBOX 0x1fe01000ULL
+#define CORE_STATUS_OFF 0x000
+#define CORE_EN_OFF 0x004
+#define CORE_SET_OFF 0x008
+#define CORE_CLEAR_OFF 0x00c
+#define CORE_BUF_20 0x020
+#define CORE_BUF_28 0x028
+#define CORE_BUF_30 0x030
+#define CORE_BUF_38 0x038
+
+#define MAX_GIPI_CORE_NUM 4
+#define MAX_GIPI_MBX_NUM 4
+
+typedef struct gipi_core {
+ uint32_t status;
+ uint32_t en;
+ uint32_t set;
+ uint32_t clear;
+ uint64_t buf[MAX_GIPI_MBX_NUM];
+ qemu_irq irq;
+} gipi_core;
+
+typedef struct gipiState {
+ gipi_core core[MAX_GIPI_CORE_NUM];
+} gipiState;
+
+#endif
@@ -13,6 +13,7 @@
#include "qemu-common.h"
#include "hw/boards.h"
#include "qemu/queue.h"
+#include "hw/loongarch/gipi.h"
#define LOONGARCH_MAX_VCPUS 4
#define PM_MMIO_ADDR 0x10080000UL
@@ -39,6 +40,7 @@ typedef struct LoongarchMachineState {
/*< private >*/
MachineState parent_obj;
+ gipiState *gipi;
} LoongarchMachineState;
#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("loongson7a")
@@ -46,4 +48,5 @@ DECLARE_INSTANCE_CHECKER(LoongarchMachineState, LOONGARCH_MACHINE,
TYPE_LOONGARCH_MACHINE)
void cpu_loongarch_init_irq(LoongArchCPU *cpu);
+int cpu_init_ipi(LoongarchMachineState *ms, qemu_irq parent, int cpu);
#endif
@@ -50,6 +50,7 @@ extern const char * const fregnames[];
#define N_IRQS 14
#define IRQ_TIMER 11
+#define IRQ_IPI 12
#define LOONGARCH_HFLAG_KU 0x00003 /* kernel/user mode mask */
#define LOONGARCH_HFLAG_UM 0x00003 /* user mode flag */