From f432962e72de4d820b11294ae3e51f2aa5643265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Wed, 31 Jan 2024 09:50:39 +0100 Subject: hw/sparc/grlib: split out the headers for each peripherals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out the headers for each peripherals and move them in their right hardware directory. Update Copyright and add SPDX-License-Identifier at the same time. Co-developed-by: Frederic Konrad Signed-off-by: Clément Chigot Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20240131085047.18458-2-chigot@adacore.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/grlib_irqmp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 3bfe254..11eef62 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -3,7 +3,9 @@ * * (Multiprocessor and extended interrupt not supported) * - * Copyright (c) 2010-2019 AdaCore + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2010-2024 AdaCore * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,7 +31,7 @@ #include "hw/sysbus.h" #include "hw/qdev-properties.h" -#include "hw/sparc/grlib.h" +#include "hw/intc/grlib_irqmp.h" #include "trace.h" #include "qapi/error.h" -- cgit v1.1 From 6bf147854395f39fe45abebe40529bf7f023aeb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Wed, 31 Jan 2024 09:50:40 +0100 Subject: hw/intc/grlib_irqmp: add ncpus property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a "ncpus" property to the "grlib-irqmp" device to be used later, this required a little refactoring of how we initialize the device (ie: use realize instead of init). Co-developed-by: Frederic Konrad Signed-off-by: Clément Chigot Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20240131085047.18458-3-chigot@adacore.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/grlib_irqmp.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 11eef62..744cd64 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -1,7 +1,7 @@ /* * QEMU GRLIB IRQMP Emulator * - * (Multiprocessor and extended interrupt not supported) + * (Extended interrupt not supported) * * SPDX-License-Identifier: MIT * @@ -63,6 +63,7 @@ struct IRQMP { MemoryRegion iomem; + unsigned int ncpus; IRQMPState *state; qemu_irq irq; }; @@ -326,33 +327,44 @@ static void grlib_irqmp_reset(DeviceState *d) irqmp->state->parent = irqmp; } -static void grlib_irqmp_init(Object *obj) +static void grlib_irqmp_realize(DeviceState *dev, Error **errp) { - IRQMP *irqmp = GRLIB_IRQMP(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + IRQMP *irqmp = GRLIB_IRQMP(dev); - qdev_init_gpio_in(DEVICE(obj), grlib_irqmp_set_irq, MAX_PILS); - qdev_init_gpio_out_named(DEVICE(obj), &irqmp->irq, "grlib-irq", 1); - memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp, + if ((!irqmp->ncpus) || (irqmp->ncpus > IRQMP_MAX_CPU)) { + error_setg(errp, "Invalid ncpus properties: " + "%u, must be 0 < ncpus =< %u.", irqmp->ncpus, + IRQMP_MAX_CPU); + } + + qdev_init_gpio_in(dev, grlib_irqmp_set_irq, MAX_PILS); + qdev_init_gpio_out_named(dev, &irqmp->irq, "grlib-irq", 1); + memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp, "irqmp", IRQMP_REG_SIZE); irqmp->state = g_malloc0(sizeof *irqmp->state); - sysbus_init_mmio(dev, &irqmp->iomem); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &irqmp->iomem); } +static Property grlib_irqmp_properties[] = { + DEFINE_PROP_UINT32("ncpus", IRQMP, ncpus, 1), + DEFINE_PROP_END_OF_LIST(), +}; + static void grlib_irqmp_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = grlib_irqmp_realize; dc->reset = grlib_irqmp_reset; + device_class_set_props(dc, grlib_irqmp_properties); } static const TypeInfo grlib_irqmp_info = { .name = TYPE_GRLIB_IRQMP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IRQMP), - .instance_init = grlib_irqmp_init, .class_init = grlib_irqmp_class_init, }; -- cgit v1.1 From 7ed9a5f626a6c932a8c869a91e6a8b3e2029f5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Wed, 31 Jan 2024 09:50:41 +0100 Subject: hw/intc/grlib_irqmp: implements the multiprocessor status register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the multiprocessor status register in grlib-irqmp and bind it to a start signal, which will be later wired in leon3-generic to start a cpu. The EIRQ and BA bits are not implemented. Based on https://gaisler.com/doc/gr712rc-usermanual.pdf, §8.3.5. Co-developed-by: Frederic Konrad Signed-off-by: Clément Chigot Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20240131085047.18458-4-chigot@adacore.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/grlib_irqmp.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 744cd64..1e073bd 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -52,6 +52,10 @@ #define FORCE_OFFSET 0x80 #define EXTENDED_OFFSET 0xC0 +/* Multiprocessor Status Register */ +#define MP_STATUS_CPU_STATUS_MASK ((1 << IRQMP_MAX_CPU)-2) +#define MP_STATUS_NCPU_SHIFT 28 + #define MAX_PILS 16 OBJECT_DECLARE_SIMPLE_TYPE(IRQMP, GRLIB_IRQMP) @@ -65,6 +69,7 @@ struct IRQMP { unsigned int ncpus; IRQMPState *state; + qemu_irq start_signal[IRQMP_MAX_CPU]; qemu_irq irq; }; @@ -72,6 +77,7 @@ struct IRQMPState { uint32_t level; uint32_t pending; uint32_t clear; + uint32_t mpstatus; uint32_t broadcast; uint32_t mask[IRQMP_MAX_CPU]; @@ -182,10 +188,12 @@ static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr, return state->force[0]; case CLEAR_OFFSET: - case MP_STATUS_OFFSET: /* Always read as 0 */ return 0; + case MP_STATUS_OFFSET: + return state->mpstatus; + case BROADCAST_OFFSET: return state->broadcast; @@ -224,8 +232,9 @@ static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr, static void grlib_irqmp_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - IRQMP *irqmp = opaque; + IRQMP *irqmp = opaque; IRQMPState *state; + int i; assert(irqmp != NULL); state = irqmp->state; @@ -258,7 +267,18 @@ static void grlib_irqmp_write(void *opaque, hwaddr addr, return; case MP_STATUS_OFFSET: - /* Read Only (no SMP support) */ + /* + * Writing and reading operations are reversed for the CPU status. + * Writing "1" will start the CPU, but reading "1" means that the CPU + * is power-down. + */ + value &= MP_STATUS_CPU_STATUS_MASK; + for (i = 0; i < irqmp->ncpus; i++) { + if ((value >> i) & 1) { + qemu_set_irq(irqmp->start_signal[i], 1); + state->mpstatus &= ~(1 << i); + } + } return; case BROADCAST_OFFSET: @@ -325,6 +345,8 @@ static void grlib_irqmp_reset(DeviceState *d) memset(irqmp->state, 0, sizeof *irqmp->state); irqmp->state->parent = irqmp; + irqmp->state->mpstatus = ((irqmp->ncpus - 1) << MP_STATUS_NCPU_SHIFT) | + ((1 << irqmp->ncpus) - 2); } static void grlib_irqmp_realize(DeviceState *dev, Error **errp) @@ -338,6 +360,13 @@ static void grlib_irqmp_realize(DeviceState *dev, Error **errp) } qdev_init_gpio_in(dev, grlib_irqmp_set_irq, MAX_PILS); + + /* + * Transitionning from 0 to 1 starts the CPUs. The opposite can't + * happen. + */ + qdev_init_gpio_out_named(dev, irqmp->start_signal, "grlib-start-cpu", + IRQMP_MAX_CPU); qdev_init_gpio_out_named(dev, &irqmp->irq, "grlib-irq", 1); memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp, "irqmp", IRQMP_REG_SIZE); -- cgit v1.1 From 0fa5cd4a6016c0dc13c2882f63b58787cf3283bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Wed, 31 Jan 2024 09:50:42 +0100 Subject: hw/intc/grlib_irqmp: implements multicore irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now there is an ncpus property, use it in order to deliver the IRQ to multiple CPU. Co-developed-by: Frederic Konrad Signed-off-by: Clément Chigot Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20240131085047.18458-5-chigot@adacore.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/grlib_irqmp.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'hw/intc') diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 1e073bd..144b121 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -70,7 +70,7 @@ struct IRQMP { unsigned int ncpus; IRQMPState *state; qemu_irq start_signal[IRQMP_MAX_CPU]; - qemu_irq irq; + qemu_irq irq[IRQMP_MAX_CPU]; }; struct IRQMPState { @@ -89,37 +89,35 @@ struct IRQMPState { static void grlib_irqmp_check_irqs(IRQMPState *state) { - uint32_t pend = 0; - uint32_t level0 = 0; - uint32_t level1 = 0; + int i; assert(state != NULL); assert(state->parent != NULL); - /* IRQ for CPU 0 (no SMP support) */ - pend = (state->pending | state->force[0]) - & state->mask[0]; - - level0 = pend & ~state->level; - level1 = pend & state->level; + for (i = 0; i < state->parent->ncpus; i++) { + uint32_t pend = (state->pending | state->force[i]) & state->mask[i]; + uint32_t level0 = pend & ~state->level; + uint32_t level1 = pend & state->level; - trace_grlib_irqmp_check_irqs(state->pending, state->force[0], - state->mask[0], level1, level0); + trace_grlib_irqmp_check_irqs(state->pending, state->force[i], + state->mask[i], level1, level0); - /* Trigger level1 interrupt first and level0 if there is no level1 */ - qemu_set_irq(state->parent->irq, level1 ?: level0); + /* Trigger level1 interrupt first and level0 if there is no level1 */ + qemu_set_irq(state->parent->irq[i], level1 ?: level0); + } } -static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask) +static void grlib_irqmp_ack_mask(IRQMPState *state, unsigned int cpu, + uint32_t mask) { /* Clear registers */ state->pending &= ~mask; - state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */ + state->force[cpu] &= ~mask; grlib_irqmp_check_irqs(state); } -void grlib_irqmp_ack(DeviceState *dev, int intno) +void grlib_irqmp_ack(DeviceState *dev, unsigned int cpu, int intno) { IRQMP *irqmp = GRLIB_IRQMP(dev); IRQMPState *state; @@ -133,7 +131,7 @@ void grlib_irqmp_ack(DeviceState *dev, int intno) trace_grlib_irqmp_ack(intno); - grlib_irqmp_ack_mask(state, mask); + grlib_irqmp_ack_mask(state, cpu, mask); } static void grlib_irqmp_set_irq(void *opaque, int irq, int level) @@ -159,7 +157,6 @@ static void grlib_irqmp_set_irq(void *opaque, int irq, int level) s->pending |= 1 << irq; } grlib_irqmp_check_irqs(s); - } } @@ -263,7 +260,9 @@ static void grlib_irqmp_write(void *opaque, hwaddr addr, case CLEAR_OFFSET: value &= ~1; /* clean up the value */ - grlib_irqmp_ack_mask(state, value); + for (i = 0; i < irqmp->ncpus; i++) { + grlib_irqmp_ack_mask(state, i, value); + } return; case MP_STATUS_OFFSET: @@ -367,7 +366,7 @@ static void grlib_irqmp_realize(DeviceState *dev, Error **errp) */ qdev_init_gpio_out_named(dev, irqmp->start_signal, "grlib-start-cpu", IRQMP_MAX_CPU); - qdev_init_gpio_out_named(dev, &irqmp->irq, "grlib-irq", 1); + qdev_init_gpio_out_named(dev, irqmp->irq, "grlib-irq", irqmp->ncpus); memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp, "irqmp", IRQMP_REG_SIZE); -- cgit v1.1