From 1eeffbeb1114441cb1822ce0af952a283e008f31 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Nov 2020 22:51:25 +0000 Subject: hw/openrisc/openrisc_sim: Use IRQ splitter when connecting IRQ to multiple CPUs openrisc_sim_net_init() attempts to connect the IRQ line from the ethernet device to both CPUs in an SMP configuration by simply caling sysbus_connect_irq() for it twice. This doesn't work, because the second connection simply overrides the first. Fix this by creating a TYPE_SPLIT_IRQ to split the IRQ in the SMP case. Signed-off-by: Peter Maydell Reviewed-by: Stafford Horne Message-id: 20201127225127.14770-2-peter.maydell@linaro.org --- hw/openrisc/openrisc_sim.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'hw/openrisc/openrisc_sim.c') diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index d752282e67..a8adf6b70d 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -34,6 +34,7 @@ #include "hw/sysbus.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" +#include "hw/core/split-irq.h" #define KERNEL_LOAD_ADDR 0x100 @@ -64,8 +65,16 @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); - for (i = 0; i < num_cpus; i++) { - sysbus_connect_irq(s, 0, cpu_irqs[i][irq_pin]); + if (num_cpus > 1) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(splitter, "num-lines", num_cpus); + qdev_realize_and_unref(splitter, NULL, &error_fatal); + for (i = 0; i < num_cpus; i++) { + qdev_connect_gpio_out(splitter, i, cpu_irqs[i][irq_pin]); + } + sysbus_connect_irq(s, 0, qdev_get_gpio_in(splitter, 0)); + } else { + sysbus_connect_irq(s, 0, cpu_irqs[0][irq_pin]); } sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, descriptors); -- cgit 1.4.1 From eaca43a0f7a3548a527e74b7d14d69eeb31dc339 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Nov 2020 22:51:26 +0000 Subject: hw/openrisc/openrisc_sim: Abstract out "get IRQ x of CPU y" We're about to refactor the OpenRISC pic_cpu code in a way that means that just grabbing the whole qemu_irq[] array of inbound IRQs for a CPU won't be possible any more. Abstract out a function for "return the qemu_irq for IRQ x input of CPU y" so we can more easily replace the implementation. Signed-off-by: Peter Maydell Reviewed-by: Stafford Horne Message-id: 20201127225127.14770-3-peter.maydell@linaro.org --- hw/openrisc/openrisc_sim.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'hw/openrisc/openrisc_sim.c') diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index a8adf6b70d..75ba0f4744 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -52,8 +52,13 @@ static void main_cpu_reset(void *opaque) cpu_set_pc(cs, boot_info.bootstrap_pc); } +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ + return cpus[cpunum]->env.irq[irq_pin]; +} + static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, - int num_cpus, qemu_irq **cpu_irqs, + int num_cpus, OpenRISCCPU *cpus[], int irq_pin, NICInfo *nd) { DeviceState *dev; @@ -70,18 +75,18 @@ static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, qdev_prop_set_uint32(splitter, "num-lines", num_cpus); qdev_realize_and_unref(splitter, NULL, &error_fatal); for (i = 0; i < num_cpus; i++) { - qdev_connect_gpio_out(splitter, i, cpu_irqs[i][irq_pin]); + qdev_connect_gpio_out(splitter, i, get_cpu_irq(cpus, i, irq_pin)); } sysbus_connect_irq(s, 0, qdev_get_gpio_in(splitter, 0)); } else { - sysbus_connect_irq(s, 0, cpu_irqs[0][irq_pin]); + sysbus_connect_irq(s, 0, get_cpu_irq(cpus, 0, irq_pin)); } sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, descriptors); } static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, - qemu_irq **cpu_irqs, int irq_pin) + OpenRISCCPU *cpus[], int irq_pin) { DeviceState *dev; SysBusDevice *s; @@ -93,7 +98,7 @@ static void openrisc_sim_ompic_init(hwaddr base, int num_cpus, s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); for (i = 0; i < num_cpus; i++) { - sysbus_connect_irq(s, i, cpu_irqs[i][irq_pin]); + sysbus_connect_irq(s, i, get_cpu_irq(cpus, i, irq_pin)); } sysbus_mmio_map(s, 0, base); } @@ -136,26 +141,24 @@ static void openrisc_sim_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; - OpenRISCCPU *cpu = NULL; + OpenRISCCPU *cpus[2] = {}; MemoryRegion *ram; - qemu_irq *cpu_irqs[2]; qemu_irq serial_irq; int n; unsigned int smp_cpus = machine->smp.cpus; assert(smp_cpus >= 1 && smp_cpus <= 2); for (n = 0; n < smp_cpus; n++) { - cpu = OPENRISC_CPU(cpu_create(machine->cpu_type)); - if (cpu == NULL) { + cpus[n] = OPENRISC_CPU(cpu_create(machine->cpu_type)); + if (cpus[n] == NULL) { fprintf(stderr, "Unable to find CPU definition!\n"); exit(1); } - cpu_openrisc_pic_init(cpu); - cpu_irqs[n] = (qemu_irq *) cpu->env.irq; + cpu_openrisc_pic_init(cpus[n]); - cpu_openrisc_clock_init(cpu); + cpu_openrisc_clock_init(cpus[n]); - qemu_register_reset(main_cpu_reset, cpu); + qemu_register_reset(main_cpu_reset, cpus[n]); } ram = g_malloc(sizeof(*ram)); @@ -164,15 +167,16 @@ static void openrisc_sim_init(MachineState *machine) if (nd_table[0].used) { openrisc_sim_net_init(0x92000000, 0x92000400, smp_cpus, - cpu_irqs, 4, nd_table); + cpus, 4, nd_table); } if (smp_cpus > 1) { - openrisc_sim_ompic_init(0x98000000, smp_cpus, cpu_irqs, 1); + openrisc_sim_ompic_init(0x98000000, smp_cpus, cpus, 1); - serial_irq = qemu_irq_split(cpu_irqs[0][2], cpu_irqs[1][2]); + serial_irq = qemu_irq_split(get_cpu_irq(cpus, 0, 2), + get_cpu_irq(cpus, 1, 2)); } else { - serial_irq = cpu_irqs[0][2]; + serial_irq = get_cpu_irq(cpus, 0, 2); } serial_mm_init(get_system_memory(), 0x90000000, 0, serial_irq, -- cgit 1.4.1 From 71b3254dd227f4c5e0a1a4005175a98e0a2cdc19 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Nov 2020 22:51:27 +0000 Subject: target/openrisc: Move pic_cpu code into CPU object proper The openrisc code uses an old style of interrupt handling, where a separate standalone set of qemu_irqs invoke a function openrisc_pic_cpu_handler() which signals the interrupt to the CPU proper by directly calling cpu_interrupt() and cpu_reset_interrupt(). Because CPU objects now inherit (indirectly) from TYPE_DEVICE, they can have GPIO input lines themselves, and the neater modern way to implement this is to simply have the CPU object itself provide the input IRQ lines. Create GPIO inputs to the OpenRISC CPU object, and make the only user of cpu_openrisc_pic_init() wire up directly to those instead. This allows us to delete the hw/openrisc/pic_cpu.c file entirely. This fixes a trivial memory leak reported by Coverity of the IRQs allocated in cpu_openrisc_pic_init(). Fixes: Coverity CID 1421934 Signed-off-by: Peter Maydell Reviewed-by: Stafford Horne Message-id: 20201127225127.14770-4-peter.maydell@linaro.org --- hw/openrisc/meson.build | 2 +- hw/openrisc/openrisc_sim.c | 3 +-- hw/openrisc/pic_cpu.c | 61 ---------------------------------------------- target/openrisc/cpu.c | 32 ++++++++++++++++++++++++ target/openrisc/cpu.h | 1 - 5 files changed, 34 insertions(+), 65 deletions(-) delete mode 100644 hw/openrisc/pic_cpu.c (limited to 'hw/openrisc/openrisc_sim.c') diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index 57c42558e1..947f63ee08 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,5 @@ openrisc_ss = ss.source_set() -openrisc_ss.add(files('pic_cpu.c', 'cputimer.c')) +openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: files('openrisc_sim.c')) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 75ba0f4744..39f1d344ae 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -54,7 +54,7 @@ static void main_cpu_reset(void *opaque) static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) { - return cpus[cpunum]->env.irq[irq_pin]; + return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); } static void openrisc_sim_net_init(hwaddr base, hwaddr descriptors, @@ -154,7 +154,6 @@ static void openrisc_sim_init(MachineState *machine) fprintf(stderr, "Unable to find CPU definition!\n"); exit(1); } - cpu_openrisc_pic_init(cpus[n]); cpu_openrisc_clock_init(cpus[n]); diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c deleted file mode 100644 index 36f9350830..0000000000 --- a/hw/openrisc/pic_cpu.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * OpenRISC Programmable Interrupt Controller support. - * - * Copyright (c) 2011-2012 Jia Liu - * Feng Gao - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "cpu.h" - -/* OpenRISC pic handler */ -static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) -{ - OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; - CPUState *cs = CPU(cpu); - uint32_t irq_bit; - - if (irq > 31 || irq < 0) { - return; - } - - irq_bit = 1U << irq; - - if (level) { - cpu->env.picsr |= irq_bit; - } else { - cpu->env.picsr &= ~irq_bit; - } - - if (cpu->env.picsr & cpu->env.picmr) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - cpu->env.picsr = 0; - } -} - -void cpu_openrisc_pic_init(OpenRISCCPU *cpu) -{ - int i; - qemu_irq *qi; - qi = qemu_allocate_irqs(openrisc_pic_cpu_handler, cpu, NR_IRQS); - - for (i = 0; i < NR_IRQS; i++) { - cpu->env.irq[i] = qi[i]; - } -} diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 5528c0918f..b0bdfbe4fe 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -65,6 +65,34 @@ static void openrisc_cpu_reset(DeviceState *dev) #endif } +#ifndef CONFIG_USER_ONLY +static void openrisc_cpu_set_irq(void *opaque, int irq, int level) +{ + OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; + CPUState *cs = CPU(cpu); + uint32_t irq_bit; + + if (irq > 31 || irq < 0) { + return; + } + + irq_bit = 1U << irq; + + if (level) { + cpu->env.picsr |= irq_bit; + } else { + cpu->env.picsr &= ~irq_bit; + } + + if (cpu->env.picsr & cpu->env.picmr) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + cpu->env.picsr = 0; + } +} +#endif + static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -88,6 +116,10 @@ static void openrisc_cpu_initfn(Object *obj) OpenRISCCPU *cpu = OPENRISC_CPU(obj); cpu_set_cpustate_pointers(cpu); + +#ifndef CONFIG_USER_ONLY + qdev_init_gpio_in_named(DEVICE(cpu), openrisc_cpu_set_irq, "IRQ", NR_IRQS); +#endif } /* CPU models */ diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index bd42faf144..82cbaeb4f8 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -293,7 +293,6 @@ typedef struct CPUOpenRISCState { uint32_t picmr; /* Interrupt mask register */ uint32_t picsr; /* Interrupt contrl register*/ #endif - void *irq[32]; /* Interrupt irq input */ } CPUOpenRISCState; /** -- cgit 1.4.1