[PATCH 06/10] hw/loongarch: Implement avec controller imput and output pins

Song Gao posted 10 patches 5 months, 1 week ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Song Gao <gaosong@loongson.cn>, Bibo Mao <maobibo@loongson.cn>, Jiaxun Yang <jiaxun.yang@flygoat.com>
There is a newer version of this series
[PATCH 06/10] hw/loongarch: Implement avec controller imput and output pins
Posted by Song Gao 5 months, 1 week ago
the AVEC controller supports 256*256 irqs, all the irqs connect CPU INT_AVEC irq

Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/intc/loongarch_avec.c | 28 ++++++++++++++++++++++++++++
 hw/loongarch/virt.c      | 11 +++++++++--
 target/loongarch/cpu.h   |  3 ++-
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/hw/intc/loongarch_avec.c b/hw/intc/loongarch_avec.c
index 50956e7e4e..c692fef43c 100644
--- a/hw/intc/loongarch_avec.c
+++ b/hw/intc/loongarch_avec.c
@@ -36,9 +36,19 @@ static const MemoryRegionOps loongarch_avec_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static void avec_irq_handler(void *opaque, int irq, int level)
+{
+    return;
+}
+
 static void loongarch_avec_realize(DeviceState *dev, Error **errp)
 {
+    LoongArchAVECState *s = LOONGARCH_AVEC(dev);
     LoongArchAVECClass *lac = LOONGARCH_AVEC_GET_CLASS(dev);
+    MachineState *machine = MACHINE(qdev_get_machine());
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    const CPUArchIdList  *id_list;
+    int i, irq;
 
     Error *local_err = NULL;
     lac->parent_realize(dev, &local_err);
@@ -47,6 +57,24 @@ static void loongarch_avec_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    assert(mc->possible_cpu_arch_ids);
+    id_list = mc->possible_cpu_arch_ids(machine);
+    s->num_cpu = id_list->len;
+    s->cpu = g_new(AVECCore, s->num_cpu);
+    if (s->cpu == NULL) {
+        error_setg(errp, "Memory allocation for AVECCore fail");
+        return;
+    }
+
+    for (i = 0; i < s->num_cpu; i++) {
+        s->cpu[i].arch_id = id_list->cpus[i].arch_id;
+        s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
+        for (irq = 0; irq < NR_VECTORS; irq++) {
+            qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[irq], 1);
+        }
+    }
+    qdev_init_gpio_in(dev, avec_irq_handler, NR_VECTORS * s->num_cpu);
+
     return;
 }
 
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 272355da2d..718b5b4f92 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -363,7 +363,7 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
     }
 }
 
-static void virt_irq_init(LoongArchVirtMachineState *lvms)
+static void virt_irq_init(LoongArchVirtMachineState *lvms, MachineState *ms)
 {
     DeviceState *pch_pic, *pch_msi;
     DeviceState *ipi, *extioi, *avec;
@@ -459,6 +459,13 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
         sysbus_realize_and_unref(SYS_BUS_DEVICE(avec), &error_fatal);
         memory_region_add_subregion(get_system_memory(), VIRT_PCH_MSI_ADDR_LOW,
                         sysbus_mmio_get_region(SYS_BUS_DEVICE(avec), 0));
+        CPUState *cpu_state;
+        DeviceState *cpudev;
+        for (int cpu = 0; cpu < ms->smp.cpus; cpu++) {
+            cpu_state = qemu_get_cpu(cpu);
+            cpudev = DEVICE(cpu_state);
+            qdev_connect_gpio_out(avec, cpu, qdev_get_gpio_in(cpudev, INT_AVEC));
+        }
     }
 
     /* Create EXTIOI device */
@@ -799,7 +806,7 @@ static void virt_init(MachineState *machine)
     }
 
     /* Initialize the IO interrupt subsystem */
-    virt_irq_init(lvms);
+    virt_irq_init(lvms, machine);
     lvms->machine_done.notify = virt_done;
     qemu_add_machine_init_done_notifier(&lvms->machine_done);
      /* connect powerdown request */
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index a1918a85da..b96df1cb2a 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -240,9 +240,10 @@ FIELD(CSR_CRMD, WE, 9, 1)
 extern const char * const regnames[32];
 extern const char * const fregnames[32];
 
-#define N_IRQS      13
+#define N_IRQS      15
 #define IRQ_TIMER   11
 #define IRQ_IPI     12
+#define INT_AVEC    14
 
 #define LOONGARCH_STLB         2048 /* 2048 STLB */
 #define LOONGARCH_MTLB         64   /* 64 MTLB */
-- 
2.34.1
Re: [PATCH 06/10] hw/loongarch: Implement avec controller imput and output pins
Posted by Bibo Mao 5 months, 1 week ago

On 2025/6/9 下午6:48, Song Gao wrote:
> the AVEC controller supports 256*256 irqs, all the irqs connect CPU INT_AVEC irq
> 
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/intc/loongarch_avec.c | 28 ++++++++++++++++++++++++++++
>   hw/loongarch/virt.c      | 11 +++++++++--
>   target/loongarch/cpu.h   |  3 ++-
>   3 files changed, 39 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/intc/loongarch_avec.c b/hw/intc/loongarch_avec.c
> index 50956e7e4e..c692fef43c 100644
> --- a/hw/intc/loongarch_avec.c
> +++ b/hw/intc/loongarch_avec.c
> @@ -36,9 +36,19 @@ static const MemoryRegionOps loongarch_avec_ops = {
>       .endianness = DEVICE_LITTLE_ENDIAN,
>   };
>   
> +static void avec_irq_handler(void *opaque, int irq, int level)
> +{
> +    return;
> +}
> +
>   static void loongarch_avec_realize(DeviceState *dev, Error **errp)
>   {
> +    LoongArchAVECState *s = LOONGARCH_AVEC(dev);
>       LoongArchAVECClass *lac = LOONGARCH_AVEC_GET_CLASS(dev);
> +    MachineState *machine = MACHINE(qdev_get_machine());
> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> +    const CPUArchIdList  *id_list;
> +    int i, irq;
>   
>       Error *local_err = NULL;
>       lac->parent_realize(dev, &local_err);
> @@ -47,6 +57,24 @@ static void loongarch_avec_realize(DeviceState *dev, Error **errp)
>           return;
>       }
>   
> +    assert(mc->possible_cpu_arch_ids);
> +    id_list = mc->possible_cpu_arch_ids(machine);
> +    s->num_cpu = id_list->len;
> +    s->cpu = g_new(AVECCore, s->num_cpu);
> +    if (s->cpu == NULL) {
> +        error_setg(errp, "Memory allocation for AVECCore fail");
> +        return;
> +    }
> +
> +    for (i = 0; i < s->num_cpu; i++) {
> +        s->cpu[i].arch_id = id_list->cpus[i].arch_id;
> +        s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
> +        for (irq = 0; irq < NR_VECTORS; irq++) {
> +            qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[irq], 1);
> +        }
One parent irqline for per-cpu is ok, so the total number of parent 
irqline is s->num_cpu, the number of possible cpu.

> +    }
> +    qdev_init_gpio_in(dev, avec_irq_handler, NR_VECTORS * s->num_cpu);
avec_irq_handler() can be removed here.

Regards
Bibo Mao
> +
>       return;
>   }
>   
> diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
> index 272355da2d..718b5b4f92 100644
> --- a/hw/loongarch/virt.c
> +++ b/hw/loongarch/virt.c
> @@ -363,7 +363,7 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
>       }
>   }
>   
> -static void virt_irq_init(LoongArchVirtMachineState *lvms)
> +static void virt_irq_init(LoongArchVirtMachineState *lvms, MachineState *ms)
>   {
>       DeviceState *pch_pic, *pch_msi;
>       DeviceState *ipi, *extioi, *avec;
> @@ -459,6 +459,13 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
>           sysbus_realize_and_unref(SYS_BUS_DEVICE(avec), &error_fatal);
>           memory_region_add_subregion(get_system_memory(), VIRT_PCH_MSI_ADDR_LOW,
>                           sysbus_mmio_get_region(SYS_BUS_DEVICE(avec), 0));
> +        CPUState *cpu_state;
> +        DeviceState *cpudev;
> +        for (int cpu = 0; cpu < ms->smp.cpus; cpu++) {
> +            cpu_state = qemu_get_cpu(cpu);
> +            cpudev = DEVICE(cpu_state);
> +            qdev_connect_gpio_out(avec, cpu, qdev_get_gpio_in(cpudev, INT_AVEC));
> +        }
>       }
>   
>       /* Create EXTIOI device */
> @@ -799,7 +806,7 @@ static void virt_init(MachineState *machine)
>       }
>   
>       /* Initialize the IO interrupt subsystem */
> -    virt_irq_init(lvms);
> +    virt_irq_init(lvms, machine);
>       lvms->machine_done.notify = virt_done;
>       qemu_add_machine_init_done_notifier(&lvms->machine_done);
>        /* connect powerdown request */
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index a1918a85da..b96df1cb2a 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -240,9 +240,10 @@ FIELD(CSR_CRMD, WE, 9, 1)
>   extern const char * const regnames[32];
>   extern const char * const fregnames[32];
>   
> -#define N_IRQS      13
> +#define N_IRQS      15
>   #define IRQ_TIMER   11
>   #define IRQ_IPI     12
> +#define INT_AVEC    14
>   
>   #define LOONGARCH_STLB         2048 /* 2048 STLB */
>   #define LOONGARCH_MTLB         64   /* 64 MTLB */
> 


Re: [PATCH 06/10] hw/loongarch: Implement avec controller imput and output pins
Posted by gaosong 5 months ago
在 2025/6/11 下午2:40, Bibo Mao 写道:
>
>
> On 2025/6/9 下午6:48, Song Gao wrote:
>> the AVEC controller supports 256*256 irqs, all the irqs connect CPU 
>> INT_AVEC irq
>>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>>   hw/intc/loongarch_avec.c | 28 ++++++++++++++++++++++++++++
>>   hw/loongarch/virt.c      | 11 +++++++++--
>>   target/loongarch/cpu.h   |  3 ++-
>>   3 files changed, 39 insertions(+), 3 deletions(-)
>>
>> diff --git a/hw/intc/loongarch_avec.c b/hw/intc/loongarch_avec.c
>> index 50956e7e4e..c692fef43c 100644
>> --- a/hw/intc/loongarch_avec.c
>> +++ b/hw/intc/loongarch_avec.c
>> @@ -36,9 +36,19 @@ static const MemoryRegionOps loongarch_avec_ops = {
>>       .endianness = DEVICE_LITTLE_ENDIAN,
>>   };
>>   +static void avec_irq_handler(void *opaque, int irq, int level)
>> +{
>> +    return;
>> +}
>> +
>>   static void loongarch_avec_realize(DeviceState *dev, Error **errp)
>>   {
>> +    LoongArchAVECState *s = LOONGARCH_AVEC(dev);
>>       LoongArchAVECClass *lac = LOONGARCH_AVEC_GET_CLASS(dev);
>> +    MachineState *machine = MACHINE(qdev_get_machine());
>> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
>> +    const CPUArchIdList  *id_list;
>> +    int i, irq;
>>         Error *local_err = NULL;
>>       lac->parent_realize(dev, &local_err);
>> @@ -47,6 +57,24 @@ static void loongarch_avec_realize(DeviceState 
>> *dev, Error **errp)
>>           return;
>>       }
>>   +    assert(mc->possible_cpu_arch_ids);
>> +    id_list = mc->possible_cpu_arch_ids(machine);
>> +    s->num_cpu = id_list->len;
>> +    s->cpu = g_new(AVECCore, s->num_cpu);
>> +    if (s->cpu == NULL) {
>> +        error_setg(errp, "Memory allocation for AVECCore fail");
>> +        return;
>> +    }
>> +
>> +    for (i = 0; i < s->num_cpu; i++) {
>> +        s->cpu[i].arch_id = id_list->cpus[i].arch_id;
>> +        s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
>> +        for (irq = 0; irq < NR_VECTORS; irq++) {
>> +            qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[irq], 1);
>> +        }
> One parent irqline for per-cpu is ok, so the total number of parent 
> irqline is s->num_cpu, the number of possible cpu.
>
emm,  yes ,  so the avec gpio out num is s->num_cpu * s->num_cpu.,
my thought   avec should  gpio_out = aveec gpio in,  and the avec gpio 
in is NR_VECTORS * s->num_cpu.
>> +    }
>> +    qdev_init_gpio_in(dev, avec_irq_handler, NR_VECTORS * s->num_cpu);
> avec_irq_handler() can be removed here.
>
yes.  i 'll remove on v2.

thanks.
Song Gao
> Regards
> Bibo Mao
>> +
>>       return;
>>   }
>>   diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
>> index 272355da2d..718b5b4f92 100644
>> --- a/hw/loongarch/virt.c
>> +++ b/hw/loongarch/virt.c
>> @@ -363,7 +363,7 @@ static void 
>> virt_cpu_irq_init(LoongArchVirtMachineState *lvms)
>>       }
>>   }
>>   -static void virt_irq_init(LoongArchVirtMachineState *lvms)
>> +static void virt_irq_init(LoongArchVirtMachineState *lvms, 
>> MachineState *ms)
>>   {
>>       DeviceState *pch_pic, *pch_msi;
>>       DeviceState *ipi, *extioi, *avec;
>> @@ -459,6 +459,13 @@ static void 
>> virt_irq_init(LoongArchVirtMachineState *lvms)
>>           sysbus_realize_and_unref(SYS_BUS_DEVICE(avec), &error_fatal);
>>           memory_region_add_subregion(get_system_memory(), 
>> VIRT_PCH_MSI_ADDR_LOW,
>> sysbus_mmio_get_region(SYS_BUS_DEVICE(avec), 0));
>> +        CPUState *cpu_state;
>> +        DeviceState *cpudev;
>> +        for (int cpu = 0; cpu < ms->smp.cpus; cpu++) {
>> +            cpu_state = qemu_get_cpu(cpu);
>> +            cpudev = DEVICE(cpu_state);
>> +            qdev_connect_gpio_out(avec, cpu, 
>> qdev_get_gpio_in(cpudev, INT_AVEC));
here connect all  avec gpio_out to  cpu gpio_in  INT_AVEC.
>> +        }
>>       }
>>         /* Create EXTIOI device */
>> @@ -799,7 +806,7 @@ static void virt_init(MachineState *machine)
>>       }
>>         /* Initialize the IO interrupt subsystem */
>> -    virt_irq_init(lvms);
>> +    virt_irq_init(lvms, machine);
>>       lvms->machine_done.notify = virt_done;
>> qemu_add_machine_init_done_notifier(&lvms->machine_done);
>>        /* connect powerdown request */
>> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
>> index a1918a85da..b96df1cb2a 100644
>> --- a/target/loongarch/cpu.h
>> +++ b/target/loongarch/cpu.h
>> @@ -240,9 +240,10 @@ FIELD(CSR_CRMD, WE, 9, 1)
>>   extern const char * const regnames[32];
>>   extern const char * const fregnames[32];
>>   -#define N_IRQS      13
>> +#define N_IRQS      15
>>   #define IRQ_TIMER   11
>>   #define IRQ_IPI     12
>> +#define INT_AVEC    14
>>     #define LOONGARCH_STLB         2048 /* 2048 STLB */
>>   #define LOONGARCH_MTLB         64   /* 64 MTLB */
>>