Message ID | 1636594528-8175-19-git-send-email-yangxiaojuan@loongson.cn (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add Loongarch softmmu support. | expand |
On 11/11/2021 01:35, Xiaojuan Yang wrote: > This patch realize the IPI interrupt controller. > > Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> > Signed-off-by: Song Gao <gaosong@loongson.cn> > --- > hw/loongarch/ipi.c | 144 +++++++++++++++++++++++++++++++ > hw/loongarch/ls3a5000_virt.c | 1 + > hw/loongarch/meson.build | 2 +- > include/hw/loongarch/gipi.h | 37 ++++++++ > include/hw/loongarch/loongarch.h | 4 + > target/loongarch/cpu.h | 1 + > 6 files changed, 188 insertions(+), 1 deletion(-) > create mode 100644 hw/loongarch/ipi.c > create mode 100644 include/hw/loongarch/gipi.h > > diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c > new file mode 100644 > index 0000000000..4902205ff5 > --- /dev/null > +++ b/hw/loongarch/ipi.c > @@ -0,0 +1,144 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * LoongArch ipi interrupt support > + * > + * Copyright (C) 2021 Loongson Technology Corporation Limited > + */ > + > +#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 *lams, qemu_irq parent, int cpu) > +{ > + int core_num = cpu % 4; > + hwaddr addr; > + MemoryRegion *region; > + char str[32]; > + > + if (lams->gipi == NULL) { > + lams->gipi = g_malloc0(sizeof(gipiState)); > + vmstate_register(NULL, 0, &vmstate_gipi, lams->gipi); > + } > + > + lams->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, > + &lams->gipi->core[cpu], str, 0x100); > + memory_region_add_subregion(lams->system_iocsr, addr, region); > + return 0; > +} This doesn't look right at all. Shouldn't this be a qdev device? Also similar to my comments on previous patches, there shouldn't really be any heap allocation used. > diff --git a/hw/loongarch/ls3a5000_virt.c b/hw/loongarch/ls3a5000_virt.c > index 37d6b1ec88..bd79df96df 100644 > --- a/hw/loongarch/ls3a5000_virt.c > +++ b/hw/loongarch/ls3a5000_virt.c > @@ -153,6 +153,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(lams, env->irq[IRQ_IPI], i); > qemu_register_reset(main_cpu_reset, cpu); > } > > diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build > index a972210680..1bd209c9eb 100644 > --- a/hw/loongarch/meson.build > +++ b/hw/loongarch/meson.build > @@ -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} > diff --git a/include/hw/loongarch/gipi.h b/include/hw/loongarch/gipi.h > new file mode 100644 > index 0000000000..244d4e3ecf > --- /dev/null > +++ b/include/hw/loongarch/gipi.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * LoongArch ipi interrupt header files > + * > + * Copyright (C) 2021 Loongson Technology Corporation Limited > + */ > + > +#ifndef HW_LOONGARCH_GIPI_H > +#define HW_LOONGARCH_GIPI_H > + > +#define SMP_GIPI_MAILBOX 0x1000ULL > +#define CORE_STATUS_OFF 0x0 > +#define CORE_EN_OFF 0x4 > +#define CORE_SET_OFF 0x8 > +#define CORE_CLEAR_OFF 0xc > +#define CORE_BUF_20 0x20 > +#define CORE_BUF_28 0x28 > +#define CORE_BUF_30 0x30 > +#define CORE_BUF_38 0x38 > + > +#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 > diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h > index 8538697e5f..54cc875e6d 100644 > --- a/include/hw/loongarch/loongarch.h > +++ b/include/hw/loongarch/loongarch.h > @@ -12,6 +12,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 > @@ -38,6 +39,8 @@ typedef struct LoongArchMachineState { > > AddressSpace *address_space_iocsr; > MemoryRegion *system_iocsr; > + > + gipiState *gipi; > } LoongArchMachineState; > > #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("loongson7a") > @@ -45,4 +48,5 @@ DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE, > TYPE_LOONGARCH_MACHINE) > > void cpu_loongarch_init_irq(LoongArchCPU *cpu); > +int cpu_init_ipi(LoongArchMachineState *lams, qemu_irq irq, int cpu); > #endif > diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h > index 77afe9e26a..b7ef0b8b3c 100644 > --- a/target/loongarch/cpu.h > +++ b/target/loongarch/cpu.h > @@ -152,6 +152,7 @@ extern const char * const fregnames[]; > > #define N_IRQS 14 > #define IRQ_TIMER 11 > +#define IRQ_IPI 12 > > /* > * LoongArch cpu has 4 priv level, now only 2 mode used. ATB, Mark.
diff --git a/hw/loongarch/ipi.c b/hw/loongarch/ipi.c new file mode 100644 index 0000000000..4902205ff5 --- /dev/null +++ b/hw/loongarch/ipi.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt support + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#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 *lams, qemu_irq parent, int cpu) +{ + int core_num = cpu % 4; + hwaddr addr; + MemoryRegion *region; + char str[32]; + + if (lams->gipi == NULL) { + lams->gipi = g_malloc0(sizeof(gipiState)); + vmstate_register(NULL, 0, &vmstate_gipi, lams->gipi); + } + + lams->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, + &lams->gipi->core[cpu], str, 0x100); + memory_region_add_subregion(lams->system_iocsr, addr, region); + return 0; +} diff --git a/hw/loongarch/ls3a5000_virt.c b/hw/loongarch/ls3a5000_virt.c index 37d6b1ec88..bd79df96df 100644 --- a/hw/loongarch/ls3a5000_virt.c +++ b/hw/loongarch/ls3a5000_virt.c @@ -153,6 +153,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(lams, env->irq[IRQ_IPI], i); qemu_register_reset(main_cpu_reset, cpu); } diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build index a972210680..1bd209c9eb 100644 --- a/hw/loongarch/meson.build +++ b/hw/loongarch/meson.build @@ -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} diff --git a/include/hw/loongarch/gipi.h b/include/hw/loongarch/gipi.h new file mode 100644 index 0000000000..244d4e3ecf --- /dev/null +++ b/include/hw/loongarch/gipi.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch ipi interrupt header files + * + * Copyright (C) 2021 Loongson Technology Corporation Limited + */ + +#ifndef HW_LOONGARCH_GIPI_H +#define HW_LOONGARCH_GIPI_H + +#define SMP_GIPI_MAILBOX 0x1000ULL +#define CORE_STATUS_OFF 0x0 +#define CORE_EN_OFF 0x4 +#define CORE_SET_OFF 0x8 +#define CORE_CLEAR_OFF 0xc +#define CORE_BUF_20 0x20 +#define CORE_BUF_28 0x28 +#define CORE_BUF_30 0x30 +#define CORE_BUF_38 0x38 + +#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 diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h index 8538697e5f..54cc875e6d 100644 --- a/include/hw/loongarch/loongarch.h +++ b/include/hw/loongarch/loongarch.h @@ -12,6 +12,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 @@ -38,6 +39,8 @@ typedef struct LoongArchMachineState { AddressSpace *address_space_iocsr; MemoryRegion *system_iocsr; + + gipiState *gipi; } LoongArchMachineState; #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("loongson7a") @@ -45,4 +48,5 @@ DECLARE_INSTANCE_CHECKER(LoongArchMachineState, LOONGARCH_MACHINE, TYPE_LOONGARCH_MACHINE) void cpu_loongarch_init_irq(LoongArchCPU *cpu); +int cpu_init_ipi(LoongArchMachineState *lams, qemu_irq irq, int cpu); #endif diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 77afe9e26a..b7ef0b8b3c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -152,6 +152,7 @@ extern const char * const fregnames[]; #define N_IRQS 14 #define IRQ_TIMER 11 +#define IRQ_IPI 12 /* * LoongArch cpu has 4 priv level, now only 2 mode used.