diff mbox series

[13/15] hw/timer/arm_timer: Fix misuse of SysBus IRQ in IcpPitState

Message ID 20230531203559.29140-14-philmd@linaro.org
State Superseded
Headers show
Series hw/timer/arm_timer: QOM'ify ARM_TIMER and correct sysbus/irq in ICP_PIT | expand

Commit Message

Philippe Mathieu-Daudé May 31, 2023, 8:35 p.m. UTC
SysBus IRQ are *output* IRQs. As some sort of simplification
to avoid to forward it, IcpPitState misuses it as ARM timer
input IRQ. Fix that by using a simple IRQ forwarder handler.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/timer/arm_timer.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

Comments

Peter Maydell June 8, 2023, 3:09 p.m. UTC | #1
On Wed, 31 May 2023 at 21:37, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> SysBus IRQ are *output* IRQs. As some sort of simplification
> to avoid to forward it, IcpPitState misuses it as ARM timer
> input IRQ. Fix that by using a simple IRQ forwarder handler.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
>  hw/timer/arm_timer.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
> index 6f444e1789..874f9b63bc 100644
> --- a/hw/timer/arm_timer.c
> +++ b/hw/timer/arm_timer.c
> @@ -352,6 +352,7 @@ struct IntegratorPitState {
>      MemoryRegion iomem;
>      ArmTimerState *timer[3];
>      qemu_irq irq_in[3];
> +    qemu_irq irq[3];
>  };
>
>  static uint64_t icp_pit_read(void *opaque, hwaddr offset,
> @@ -391,6 +392,13 @@ static const MemoryRegionOps icp_pit_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>
> +static void icp_pit_fwd_irq(void *opaque, int n, int level)
> +{
> +    IntegratorPitState *s = opaque;
> +
> +    qemu_set_irq(s->irq[n], level);
> +}
> +
>  static void icp_pit_init(Object *obj)
>  {
>      static const uint32_t tmr_freq[] = {
> @@ -402,9 +410,14 @@ static void icp_pit_init(Object *obj)
>      IntegratorPitState *s = INTEGRATOR_PIT(obj);
>      SysBusDevice *dev = SYS_BUS_DEVICE(obj);
>
> +    qdev_init_gpio_in_named(DEVICE(obj), icp_pit_fwd_irq,
> +                            "timer-in", ARRAY_SIZE(s->timer));
> +
>      for (unsigned i = 0; i < ARRAY_SIZE(s->timer); i++) {
>          s->timer[i] = arm_timer_new(tmr_freq[i], s->irq_in[i]);
> -        sysbus_init_irq(dev, &s->irq_in[i]);
> +        sysbus_init_irq(dev, &s->irq[i]);
> +        sysbus_connect_irq(dev, i,
> +                           qdev_get_gpio_in_named(DEVICE(obj), "timer-in", i));
>      }

This feels a bit clunky but I think it's what we have to do,
since the various _pass_ APIs for forwarding GPIOs and
IRQs from a container to an inner device only work with
an entire set of IRQs.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Philippe Mathieu-Daudé July 4, 2023, 2:25 p.m. UTC | #2
On 8/6/23 17:09, Peter Maydell wrote:
> On Wed, 31 May 2023 at 21:37, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>>
>> SysBus IRQ are *output* IRQs. As some sort of simplification
>> to avoid to forward it, IcpPitState misuses it as ARM timer
>> input IRQ. Fix that by using a simple IRQ forwarder handler.
>>
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>> ---
>>   hw/timer/arm_timer.c | 15 ++++++++++++++-
>>   1 file changed, 14 insertions(+), 1 deletion(-)


>> +static void icp_pit_fwd_irq(void *opaque, int n, int level)
>> +{
>> +    IntegratorPitState *s = opaque;
>> +
>> +    qemu_set_irq(s->irq[n], level);
>> +}
>> +
>>   static void icp_pit_init(Object *obj)
>>   {
>>       static const uint32_t tmr_freq[] = {
>> @@ -402,9 +410,14 @@ static void icp_pit_init(Object *obj)
>>       IntegratorPitState *s = INTEGRATOR_PIT(obj);
>>       SysBusDevice *dev = SYS_BUS_DEVICE(obj);
>>
>> +    qdev_init_gpio_in_named(DEVICE(obj), icp_pit_fwd_irq,
>> +                            "timer-in", ARRAY_SIZE(s->timer));
>> +
>>       for (unsigned i = 0; i < ARRAY_SIZE(s->timer); i++) {
>>           s->timer[i] = arm_timer_new(tmr_freq[i], s->irq_in[i]);
>> -        sysbus_init_irq(dev, &s->irq_in[i]);
>> +        sysbus_init_irq(dev, &s->irq[i]);
>> +        sysbus_connect_irq(dev, i,
>> +                           qdev_get_gpio_in_named(DEVICE(obj), "timer-in", i));
>>       }
> 
> This feels a bit clunky but I think it's what we have to do,
> since the various _pass_ APIs for forwarding GPIOs and
> IRQs from a container to an inner device only work with
> an entire set of IRQs.

Indeed. sysbus_pass_irq() could resolve the last unused IRQ index
and amend starting at that index, but this doesn't seem a lot of
need for a such use (so far). We might consider it if we ever merge
sysbus IRQ API into qdev.

> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Thanks!

Phil.
diff mbox series

Patch

diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index 6f444e1789..874f9b63bc 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -352,6 +352,7 @@  struct IntegratorPitState {
     MemoryRegion iomem;
     ArmTimerState *timer[3];
     qemu_irq irq_in[3];
+    qemu_irq irq[3];
 };
 
 static uint64_t icp_pit_read(void *opaque, hwaddr offset,
@@ -391,6 +392,13 @@  static const MemoryRegionOps icp_pit_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
+static void icp_pit_fwd_irq(void *opaque, int n, int level)
+{
+    IntegratorPitState *s = opaque;
+
+    qemu_set_irq(s->irq[n], level);
+}
+
 static void icp_pit_init(Object *obj)
 {
     static const uint32_t tmr_freq[] = {
@@ -402,9 +410,14 @@  static void icp_pit_init(Object *obj)
     IntegratorPitState *s = INTEGRATOR_PIT(obj);
     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 
+    qdev_init_gpio_in_named(DEVICE(obj), icp_pit_fwd_irq,
+                            "timer-in", ARRAY_SIZE(s->timer));
+
     for (unsigned i = 0; i < ARRAY_SIZE(s->timer); i++) {
         s->timer[i] = arm_timer_new(tmr_freq[i], s->irq_in[i]);
-        sysbus_init_irq(dev, &s->irq_in[i]);
+        sysbus_init_irq(dev, &s->irq[i]);
+        sysbus_connect_irq(dev, i,
+                           qdev_get_gpio_in_named(DEVICE(obj), "timer-in", i));
     }
 
     memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,