@@ -282,9 +282,6 @@ static void loongarch_extioi_instance_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
for (cpu = 0; cpu < EXTIOI_CPUS; cpu++) {
- memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops,
- s, "extioi_iocsr", 0x900);
- sysbus_init_mmio(dev, &s->extioi_iocsr_mem[cpu]);
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
}
@@ -9,6 +9,7 @@
#include "hw/sysbus.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/irq.h"
+#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "exec/address-spaces.h"
@@ -26,7 +27,7 @@ static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr addr,
uint64_t ret = 0;
int index = 0;
- s = &ipi->ipi_core;
+ s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
switch (addr) {
case CORE_STATUS_OFF:
@@ -65,7 +66,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr,
* if the mask is 0, we need not to do anything.
*/
if ((val >> 27) & 0xf) {
- data = address_space_ldl(&env->address_space_iocsr, addr,
+ data = address_space_ldl(env->address_space_iocsr, addr,
attrs, NULL);
for (i = 0; i < 4; i++) {
/* get mask for byte writing */
@@ -77,7 +78,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr,
data &= mask;
data |= (val >> 32) & ~mask;
- address_space_stl(&env->address_space_iocsr, addr,
+ address_space_stl(env->address_space_iocsr, addr,
data, attrs, NULL);
}
@@ -172,7 +173,7 @@ static MemTxResult loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
uint8_t vector;
CPUState *cs;
- s = &ipi->ipi_core;
+ s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
trace_loongarch_ipi_write(size, (uint64_t)addr, val);
switch (addr) {
@@ -214,7 +215,6 @@ static MemTxResult loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
/* override requester_id */
attrs.requester_id = cs->cpu_index;
- ipi = LOONGARCH_IPI(LOONGARCH_CPU(cs)->env.ipistate);
loongarch_ipi_writel(ipi, CORE_SET_OFF, BIT(vector), 4, attrs);
break;
default:
@@ -265,12 +265,18 @@ static const MemoryRegionOps loongarch_ipi64_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void loongarch_ipi_init(Object *obj)
+static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
{
- LoongArchIPI *s = LOONGARCH_IPI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ LoongArchIPI *s = LOONGARCH_IPI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ int i;
+
+ if (s->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
- memory_region_init_io(&s->ipi_iocsr_mem, obj, &loongarch_ipi_ops,
+ memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), &loongarch_ipi_ops,
s, "loongarch_ipi_iocsr", 0x48);
/* loongarch_ipi_iocsr performs re-entrant IO through ipi_send */
@@ -278,10 +284,20 @@ static void loongarch_ipi_init(Object *obj)
sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
- memory_region_init_io(&s->ipi64_iocsr_mem, obj, &loongarch_ipi64_ops,
+ memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
+ &loongarch_ipi64_ops,
s, "loongarch_ipi64_iocsr", 0x118);
sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
- qdev_init_gpio_out(DEVICE(obj), &s->ipi_core.irq, 1);
+
+ s->cpu = g_new0(IPICore, s->num_cpu);
+ if (s->cpu == NULL) {
+ error_setg(errp, "Memory allocation for ExtIOICore faile");
+ return;
+ }
+
+ for (i = 0; i < s->num_cpu; i++) {
+ qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
+ }
}
static const VMStateDescription vmstate_ipi_core = {
@@ -300,27 +316,42 @@ static const VMStateDescription vmstate_ipi_core = {
static const VMStateDescription vmstate_loongarch_ipi = {
.name = TYPE_LOONGARCH_IPI,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
- VMSTATE_STRUCT(ipi_core, LoongArchIPI, 0, vmstate_ipi_core, IPICore),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchIPI, num_cpu,
+ vmstate_ipi_core, IPICore),
VMSTATE_END_OF_LIST()
}
};
+static Property ipi_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", LoongArchIPI, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = loongarch_ipi_realize;
+ device_class_set_props(dc, ipi_properties);
dc->vmsd = &vmstate_loongarch_ipi;
}
+static void loongarch_ipi_finalize(Object *obj)
+{
+ LoongArchIPI *s = LOONGARCH_IPI(obj);
+
+ g_free(s->cpu);
+}
+
static const TypeInfo loongarch_ipi_info = {
.name = TYPE_LOONGARCH_IPI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(LoongArchIPI),
- .instance_init = loongarch_ipi_init,
.class_init = loongarch_ipi_class_init,
+ .instance_finalize = loongarch_ipi_finalize,
};
static void loongarch_ipi_register_types(void)
@@ -535,9 +535,6 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
CPUState *cpu_state;
int cpu, pin, i, start, num;
- extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
-
/*
* The connection of interrupts:
* +-----+ +---------+ +-------+
@@ -559,36 +556,36 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
* | UARTs | | Devices | | Devices |
* +--------+ +---------+ +---------+
*/
+
+ /* Create IPI device */
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
+ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+
+ /* IPI iocsr memory region */
+ memory_region_add_subregion(&lams->system_iocsr, SMP_IPI_MAILBOX,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
+ memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
cpu_state = qemu_get_cpu(cpu);
cpudev = DEVICE(cpu_state);
lacpu = LOONGARCH_CPU(cpu_state);
env = &(lacpu->env);
-
- ipi = qdev_new(TYPE_LOONGARCH_IPI);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ env->address_space_iocsr = &lams->as_iocsr;
/* connect ipi irq to cpu irq */
- qdev_connect_gpio_out(ipi, 0, qdev_get_gpio_in(cpudev, IRQ_IPI));
- /* IPI iocsr memory region */
- memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
- 0));
- memory_region_add_subregion(&env->system_iocsr, MAIL_SEND_ADDR,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
- 1));
- /*
- * extioi iocsr memory region
- * only one extioi is added on loongarch virt machine
- * external device interrupt can only be routed to cpu 0-3
- */
- if (cpu < EXTIOI_CPUS)
- memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
- cpu));
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
env->ipistate = ipi;
}
+ /* Create EXTIOI device */
+ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ memory_region_add_subregion(&lams->system_iocsr, APIC_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+
/*
* connect ext irq to the cpu irq
* cpu_pin[9:2] <= intc_pin[7:0]
@@ -733,6 +730,43 @@ static void loongarch_direct_kernel_boot(LoongArchMachineState *lams,
}
}
+static void loongarch_qemu_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+}
+
+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
+{
+ switch (addr) {
+ case VERSION_REG:
+ return 0x11ULL;
+ case FEATURE_REG:
+ return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
+ 1ULL << IOCSRF_CSRIPI;
+ case VENDOR_REG:
+ return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
+ case CPUNAME_REG:
+ return 0x303030354133ULL; /* "3A5000" */
+ case MISC_FUNC_REG:
+ return 1ULL << IOCSRM_EXTIOI_EN;
+ }
+ return 0ULL;
+}
+
+static const MemoryRegionOps loongarch_qemu_ops = {
+ .read = loongarch_qemu_read,
+ .write = loongarch_qemu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
static void loongarch_init(MachineState *machine)
{
LoongArchCPU *lacpu;
@@ -761,8 +795,17 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
create_fdt(lams);
- /* Init CPUs */
+ /* Create IOCSR space */
+ memory_region_init_io(&lams->system_iocsr, OBJECT(machine), NULL,
+ machine, "iocsr", UINT64_MAX);
+ address_space_init(&lams->as_iocsr, &lams->system_iocsr, "IOCSR");
+ memory_region_init_io(&lams->iocsr_mem, OBJECT(machine),
+ &loongarch_qemu_ops,
+ machine, "iocsr_misc", 0x428);
+ memory_region_add_subregion(&lams->system_iocsr, 0, &lams->iocsr_mem);
+
+ /* Init CPUs */
possible_cpus = mc->possible_cpu_arch_ids(machine);
for (i = 0; i < possible_cpus->len; i++) {
cpu = cpu_create(machine->cpu_type);
@@ -58,7 +58,6 @@ struct LoongArchExtIOI {
uint8_t sw_coremap[EXTIOI_IRQS];
qemu_irq parent_irq[EXTIOI_CPUS][LS3A_INTC_IP];
qemu_irq irq[EXTIOI_IRQS];
- MemoryRegion extioi_iocsr_mem[EXTIOI_CPUS];
MemoryRegion extioi_system_mem;
};
#endif /* LOONGARCH_EXTIOI_H */
@@ -47,7 +47,8 @@ struct LoongArchIPI {
SysBusDevice parent_obj;
MemoryRegion ipi_iocsr_mem;
MemoryRegion ipi64_iocsr_mem;
- IPICore ipi_core;
+ uint32_t num_cpu;
+ IPICore *cpu;
};
#endif
@@ -50,6 +50,9 @@ struct LoongArchMachineState {
DeviceState *platform_bus_dev;
PCIBus *pci_bus;
PFlashCFI01 *flash;
+ MemoryRegion system_iocsr;
+ MemoryRegion iocsr_mem;
+ AddressSpace as_iocsr;
};
#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")
@@ -589,47 +589,6 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
lacc->parent_realize(dev, errp);
}
-#ifndef CONFIG_USER_ONLY
-static void loongarch_qemu_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- qemu_log_mask(LOG_UNIMP, "[%s]: Unimplemented reg 0x%" HWADDR_PRIx "\n",
- __func__, addr);
-}
-
-static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
-{
- switch (addr) {
- case VERSION_REG:
- return 0x11ULL;
- case FEATURE_REG:
- return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
- 1ULL << IOCSRF_CSRIPI;
- case VENDOR_REG:
- return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
- case CPUNAME_REG:
- return 0x303030354133ULL; /* "3A5000" */
- case MISC_FUNC_REG:
- return 1ULL << IOCSRM_EXTIOI_EN;
- }
- return 0ULL;
-}
-
-static const MemoryRegionOps loongarch_qemu_ops = {
- .read = loongarch_qemu_read,
- .write = loongarch_qemu_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 8,
- },
- .impl = {
- .min_access_size = 8,
- .max_access_size = 8,
- },
-};
-#endif
-
static bool loongarch_get_lsx(Object *obj, Error **errp)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@@ -700,19 +659,12 @@ static void loongarch_cpu_init(Object *obj)
{
#ifndef CONFIG_USER_ONLY
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
- CPULoongArchState *env = &cpu->env;
qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
#ifdef CONFIG_TCG
timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
&loongarch_constant_timer_cb, cpu);
#endif
- memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL,
- env, "iocsr", UINT64_MAX);
- address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
- memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
- NULL, "iocsr_misc", 0x428);
- memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
#endif
}
@@ -355,9 +355,7 @@ typedef struct CPUArchState {
#ifndef CONFIG_USER_ONLY
LoongArchTLB tlb[LOONGARCH_TLB_MAX];
- AddressSpace address_space_iocsr;
- MemoryRegion system_iocsr;
- MemoryRegion iocsr_mem;
+ AddressSpace *address_space_iocsr;
bool load_elf;
uint64_t elf_address;
uint32_t mp_state;
@@ -733,7 +733,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
trace_kvm_arch_handle_exit(run->exit_reason);
switch (run->exit_reason) {
case KVM_EXIT_LOONGARCH_IOCSR:
- address_space_rw(&env->address_space_iocsr,
+ address_space_rw(env->address_space_iocsr,
run->iocsr_io.phys_addr,
attrs,
run->iocsr_io.data,
@@ -17,52 +17,52 @@
uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr)
{
- return address_space_ldub(&env->address_space_iocsr, r_addr,
+ return address_space_ldub(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr)
{
- return address_space_lduw(&env->address_space_iocsr, r_addr,
+ return address_space_lduw(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr)
{
- return address_space_ldl(&env->address_space_iocsr, r_addr,
+ return address_space_ldl(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr)
{
- return address_space_ldq(&env->address_space_iocsr, r_addr,
+ return address_space_ldq(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
- address_space_stb(&env->address_space_iocsr, w_addr,
+ address_space_stb(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
- address_space_stw(&env->address_space_iocsr, w_addr,
+ address_space_stw(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
- address_space_stl(&env->address_space_iocsr, w_addr,
+ address_space_stl(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
- address_space_stq(&env->address_space_iocsr, w_addr,
+ address_space_stq(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}