aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiaxun Yang <jiaxun.yang@flygoat.com>2024-05-08 14:06:49 +0100
committerPhilippe Mathieu-Daudé <philmd@linaro.org>2024-06-19 12:42:03 +0200
commit49eba52a52fec563af83a77d5ec5c59dba412127 (patch)
treee2528608c1386ba7057d74ebea2c4c51ea670eaf
parent5f82fb2a3a71bb510b3e1b7229929d468c01740a (diff)
downloadqemu-49eba52a52fec563af83a77d5ec5c59dba412127.zip
qemu-49eba52a52fec563af83a77d5ec5c59dba412127.tar.gz
qemu-49eba52a52fec563af83a77d5ec5c59dba412127.tar.bz2
hw/intc/loongson_ipi: Provide per core MMIO address spaces
The real IPI hardware have dedicated MMIO registers mapped into memory address space for every core. This is not used by LoongArch guest software but it is essential for CPU without IOCSR such as Loongson-3A1000. Implement it with existing infrastructure. Acked-by: Song Gao <gaosong@loongson.cn> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Message-ID: <20240605-loongson3-ipi-v3-2-ddd2c0e03fa3@flygoat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
-rw-r--r--hw/intc/loongson_ipi.c86
-rw-r--r--include/hw/intc/loongson_ipi.h2
2 files changed, 67 insertions, 21 deletions
diff --git a/hw/intc/loongson_ipi.c b/hw/intc/loongson_ipi.c
index 93cc50a..08a74a0 100644
--- a/hw/intc/loongson_ipi.c
+++ b/hw/intc/loongson_ipi.c
@@ -23,16 +23,14 @@
#endif
#include "trace.h"
-static MemTxResult loongson_ipi_readl(void *opaque, hwaddr addr,
- uint64_t *data,
- unsigned size, MemTxAttrs attrs)
+static MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr,
+ uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
{
- IPICore *s;
- LoongsonIPI *ipi = opaque;
+ IPICore *s = opaque;
uint64_t ret = 0;
int index = 0;
- s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
switch (addr) {
case CORE_STATUS_OFF:
@@ -61,6 +59,21 @@ static MemTxResult loongson_ipi_readl(void *opaque, hwaddr addr,
return MEMTX_OK;
}
+static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
+ uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+ LoongsonIPI *ipi = opaque;
+ IPICore *s;
+
+ if (attrs.requester_id >= ipi->num_cpu) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ s = &ipi->cpu[attrs.requester_id];
+ return loongson_ipi_core_readl(s, addr, data, size, attrs);
+}
+
static AddressSpace *get_cpu_iocsr_as(CPUState *cpu)
{
#ifdef TARGET_LOONGARCH64
@@ -174,17 +187,17 @@ static MemTxResult any_send(uint64_t val, MemTxAttrs attrs)
return send_ipi_data(cs, val, addr, attrs);
}
-static MemTxResult loongson_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
- unsigned size, MemTxAttrs attrs)
+static MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
{
- LoongsonIPI *ipi = opaque;
- IPICore *s;
+ IPICore *s = opaque;
+ LoongsonIPI *ipi = s->ipi;
int index = 0;
uint32_t cpuid;
uint8_t vector;
CPUState *cs;
- s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
trace_loongson_ipi_write(size, (uint64_t)addr, val);
switch (addr) {
@@ -215,13 +228,11 @@ static MemTxResult loongson_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
/* IPI status vector */
vector = extract8(val, 0, 5);
cs = ipi_getcpu(cpuid);
- if (cs == NULL) {
+ if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
return MEMTX_DECODE_ERROR;
}
-
- /* override requester_id */
- attrs.requester_id = cs->cpu_index;
- loongson_ipi_writel(ipi, CORE_SET_OFF, BIT(vector), 4, attrs);
+ loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF,
+ BIT(vector), 4, attrs);
break;
default:
qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
@@ -231,9 +242,34 @@ static MemTxResult loongson_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
return MEMTX_OK;
}
-static const MemoryRegionOps loongson_ipi_ops = {
- .read_with_attrs = loongson_ipi_readl,
- .write_with_attrs = loongson_ipi_writel,
+static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
+{
+ LoongsonIPI *ipi = opaque;
+ IPICore *s;
+
+ if (attrs.requester_id >= ipi->num_cpu) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ s = &ipi->cpu[attrs.requester_id];
+ return loongson_ipi_core_writel(s, addr, val, size, attrs);
+}
+
+static const MemoryRegionOps loongson_ipi_core_ops = {
+ .read_with_attrs = loongson_ipi_core_readl,
+ .write_with_attrs = loongson_ipi_core_writel,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps loongson_ipi_iocsr_ops = {
+ .read_with_attrs = loongson_ipi_iocsr_readl,
+ .write_with_attrs = loongson_ipi_iocsr_writel,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
.valid.min_access_size = 4,
@@ -282,7 +318,8 @@ static void loongson_ipi_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), &loongson_ipi_ops,
+ memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
+ &loongson_ipi_iocsr_ops,
s, "loongson_ipi_iocsr", 0x48);
/* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
@@ -297,11 +334,18 @@ static void loongson_ipi_realize(DeviceState *dev, Error **errp)
s->cpu = g_new0(IPICore, s->num_cpu);
if (s->cpu == NULL) {
- error_setg(errp, "Memory allocation for ExtIOICore faile");
+ error_setg(errp, "Memory allocation for IPICore faile");
return;
}
for (i = 0; i < s->num_cpu; i++) {
+ s->cpu[i].ipi = s;
+ s->cpu[i].ipi_mmio_mem = g_new0(MemoryRegion, 1);
+ g_autofree char *name = g_strdup_printf("loongson_ipi_cpu%d_mmio", i);
+ memory_region_init_io(s->cpu[i].ipi_mmio_mem, OBJECT(dev),
+ &loongson_ipi_core_ops, &s->cpu[i], name, 0x48);
+ sysbus_init_mmio(sbd, s->cpu[i].ipi_mmio_mem);
+
qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
}
}
diff --git a/include/hw/intc/loongson_ipi.h b/include/hw/intc/loongson_ipi.h
index 2c0e882..3f795ed 100644
--- a/include/hw/intc/loongson_ipi.h
+++ b/include/hw/intc/loongson_ipi.h
@@ -34,6 +34,8 @@
OBJECT_DECLARE_SIMPLE_TYPE(LoongsonIPI, LOONGSON_IPI)
typedef struct IPICore {
+ LoongsonIPI *ipi;
+ MemoryRegion *ipi_mmio_mem;
uint32_t status;
uint32_t en;
uint32_t set;