On Tue, 12 Nov 2024 10:17:35 +0800
Bibo Mao <maob...@loongson.cn> wrote:

> Here generic function virt_init_cpu_irq() is added to init interrupt
> pin of CPU object, IPI and extioi interrupt controllers are connected
> to interrupt pin of CPU object.
> 
> The generic function can be used to both cold-plug and hot-plug CPUs.

this patch is heavily depends on cpu_index and specific order CPUs
are created.

> 
> Signed-off-by: Bibo Mao <maob...@loongson.cn>
> ---
>  hw/loongarch/virt.c         | 78 ++++++++++++++++++++++++-------------
>  include/hw/loongarch/virt.h |  2 +
>  2 files changed, 53 insertions(+), 27 deletions(-)
> 
> diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
> index b6b616d278..621380e2b3 100644
> --- a/hw/loongarch/virt.c
> +++ b/hw/loongarch/virt.c
> @@ -58,6 +58,20 @@ static bool 
> virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
>      return true;
>  }
>  
> +static CPUState *virt_get_cpu(MachineState *ms, int index)
> +{
> +    MachineClass *mc = MACHINE_GET_CLASS(ms);
> +    const CPUArchIdList *possible_cpus;
> +
> +    /* Init CPUs */
> +    possible_cpus = mc->possible_cpu_arch_ids(ms);
> +    if (index < 0 || index >= possible_cpus->len) {
> +        return NULL;
> +    }
> +
> +    return possible_cpus->cpus[index].cpu;
> +}

instead of adding this helper I'd suggest to try reusing
virt_find_cpu_slot() added in previous patch.

> +
>  static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
>                                void *opaque, Error **errp)
>  {
> @@ -365,7 +379,7 @@ static void create_fdt(LoongArchVirtMachineState *lvms)
>  static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
>  {
>      int num;
> -    const MachineState *ms = MACHINE(lvms);
> +    MachineState *ms = MACHINE(lvms);
>      int smp_cpus = ms->smp.cpus;
>  
>      qemu_fdt_add_subnode(ms->fdt, "/cpus");
> @@ -375,7 +389,7 @@ static void fdt_add_cpu_nodes(const 
> LoongArchVirtMachineState *lvms)
>      /* cpu nodes */
>      for (num = smp_cpus - 1; num >= 0; num--) {

loops based on smp_cpus become broken as soon as you have
 '-smp x, -device your-cpu,...
since it doesn't take in account '-device' created CPUs.
You likely need to replace such loops to iterate over possible_cpus
(in a separate patch please)
  
>          char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
> -        LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
> +        LoongArchCPU *cpu = LOONGARCH_CPU(virt_get_cpu(ms, num));
>          CPUState *cs = CPU(cpu);
>  
>          qemu_fdt_add_subnode(ms->fdt, nodename);
> @@ -783,16 +797,42 @@ static void virt_devices_init(DeviceState *pch_pic,
>      lvms->platform_bus_dev = create_platform_bus(pch_pic);
>  }
>  
> +static void virt_init_cpu_irq(MachineState *ms, CPUState *cs)
> +{
> +    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> +    CPULoongArchState *env;
> +    LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
> +    int pin;
> +
> +    if (!lvms->ipi || !lvms->extioi) {
> +        return;
> +    }
> +
> +    env = &(cpu->env);
> +    env->address_space_iocsr = &lvms->as_iocsr;
> +    env->ipistate = lvms->ipi;
> +    /* connect ipi irq to cpu irq, logic cpu index used here */
> +    qdev_connect_gpio_out(lvms->ipi, cs->cpu_index,
I'd try to avoid using cpu_index (basically internal CPU detail) when
wiring components together. It would be better to implement this the way
the real hw does it.


> +                              qdev_get_gpio_in(DEVICE(cs), IRQ_IPI));
> +
> +    /*
> +     * connect ext irq to the cpu irq
> +     * cpu_pin[9:2] <= intc_pin[7:0]
> +     */
> +    for (pin = 0; pin < LS3A_INTC_IP; pin++) {
> +        qdev_connect_gpio_out(lvms->extioi, cs->cpu_index * LS3A_INTC_IP + 
> pin,
> +                              qdev_get_gpio_in(DEVICE(cs), pin + 2));
> +    }
> +}
> +
>  static void virt_irq_init(LoongArchVirtMachineState *lvms)
>  {
>      MachineState *ms = MACHINE(lvms);
> -    DeviceState *pch_pic, *pch_msi, *cpudev;
> +    DeviceState *pch_pic, *pch_msi;
>      DeviceState *ipi, *extioi;
>      SysBusDevice *d;
> -    LoongArchCPU *lacpu;
> -    CPULoongArchState *env;
>      CPUState *cpu_state;
> -    int cpu, pin, i, start, num;
> +    int cpu, i, start, num;
>      uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, 
> pch_msi_phandle;
>  
>      /*
> @@ -843,6 +883,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
>      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);
> +    lvms->ipi = ipi;
>  
>      /* IPI iocsr memory region */
>      memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
> @@ -853,18 +894,6 @@ static void virt_irq_init(LoongArchVirtMachineState 
> *lvms)
>      /* Add cpu interrupt-controller */
>      fdt_add_cpuic_node(lvms, &cpuintc_phandle);
>  
> -    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);
> -        env->address_space_iocsr = &lvms->as_iocsr;
> -
> -        /* connect ipi irq to cpu irq */
> -        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);
>      qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
> @@ -872,6 +901,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
>          qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
>      }
>      sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
> +    lvms->extioi = extioi;
>      memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
>                      sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
>      if (virt_is_veiointc_enabled(lvms)) {
> @@ -879,16 +909,10 @@ static void virt_irq_init(LoongArchVirtMachineState 
> *lvms)
>                      sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
>      }
>  
> -    /*
> -     * connect ext irq to the cpu irq
> -     * cpu_pin[9:2] <= intc_pin[7:0]
> -     */
> +    /* Connect irq to cpu, including ipi and extioi irqchip */
>      for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
> -        cpudev = DEVICE(qemu_get_cpu(cpu));
> -        for (pin = 0; pin < LS3A_INTC_IP; pin++) {
> -            qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
> -                                  qdev_get_gpio_in(cpudev, pin + 2));
> -        }
> +        cpu_state = virt_get_cpu(ms, cpu);
> +        virt_init_cpu_irq(ms, cpu_state);
>      }
>  
>      /* Add Extend I/O Interrupt Controller node */
> diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
> index 9ba47793ef..260e6bd7cf 100644
> --- a/include/hw/loongarch/virt.h
> +++ b/include/hw/loongarch/virt.h
> @@ -60,6 +60,8 @@ struct LoongArchVirtMachineState {
>      MemoryRegion iocsr_mem;
>      AddressSpace as_iocsr;
>      struct loongarch_boot_info bootinfo;
> +    DeviceState *ipi;
> +    DeviceState *extioi;
>  };
>  
>  #define TYPE_LOONGARCH_VIRT_MACHINE  MACHINE_TYPE_NAME("virt")


Reply via email to