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.
Co-developed-by: Frederic Konrad <konrad.frede...@yahoo.fr> Signed-off-by: Clément Chigot <chi...@adacore.com> --- hw/intc/grlib_irqmp.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 2bacc0ff56..be0e840181 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -63,6 +63,7 @@ struct IRQMP { unsigned int ncpus; IRQMPState *state; + qemu_irq start_signal[IRQMP_MAX_CPU]; qemu_irq irq; }; @@ -70,6 +71,7 @@ struct IRQMPState { uint32_t level; uint32_t pending; uint32_t clear; + uint32_t mpstatus; uint32_t broadcast; uint32_t mask[IRQMP_MAX_CPU]; @@ -180,10 +182,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; @@ -222,8 +226,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; @@ -256,7 +261,13 @@ static void grlib_irqmp_write(void *opaque, hwaddr addr, return; case MP_STATUS_OFFSET: - /* Read Only (no SMP support) */ + value &= 0xffff; + 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: @@ -323,6 +334,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) << 28) + | ((1 << irqmp->ncpus) - 2); } static void grlib_irqmp_realize(DeviceState *dev, Error **errp) @@ -336,6 +349,9 @@ 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. */ + 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); -- 2.25.1