IO_BANK0, IO_QSPI and SIO expose interrupt state separately for each
processor. Preserve that distinction in the SoC instead of feeding the
banked outputs through the shared interrupt path.

Add the missing IO_QSPI outputs and exercise both processor interrupt lines
in qtest. Keep all banked sources behind the per-core SYSCFG NMI routing.

Signed-off-by: Gilles Grimaud <[email protected]>
---
 hw/arm/rp2040.c                  | 42 ++++++++++++++++++++++++++------
 hw/misc/rp2040_ioqspi.c          | 18 ++++++++++++++
 include/hw/arm/rp2040.h          |  3 ++-
 include/hw/misc/rp2040_ioqspi.h  |  2 ++
 tests/qtest/rp2040-ioqspi-test.c | 22 +++++++++++++++++
 5 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/hw/arm/rp2040.c b/hw/arm/rp2040.c
index 572fff0c7d..b093ad32f1 100644
--- a/hw/arm/rp2040.c
+++ b/hw/arm/rp2040.c
@@ -34,6 +34,7 @@
 #define RP2040_DMA_IRQ_0  11
 #define RP2040_DMA_IRQ_1  12
 #define RP2040_IO_IRQ_BANK0 13
+#define RP2040_IO_IRQ_QSPI 14
 #define RP2040_SIO_IRQ_PROC0 15
 #define RP2040_SIO_IRQ_PROC1 16
 
@@ -1474,8 +1475,8 @@ static void rp2040_update_nmi(RP2040State *s)
             bool route_to_nmi = nmi_mask & BIT(irq);
 
             qemu_set_irq(s->cpu_irq[core][irq],
-                         s->irq_level[irq] && !route_to_nmi);
-            nmi_level |= s->irq_level[irq] && route_to_nmi;
+                         s->irq_level[core][irq] && !route_to_nmi);
+            nmi_level |= s->irq_level[core][irq] && route_to_nmi;
         }
         qemu_set_irq(s->nmi_irq[core], nmi_level);
     }
@@ -1491,7 +1492,26 @@ static void rp2040_set_irq(void *opaque, int irq, int 
level)
     RP2040State *s = opaque;
 
     assert(irq >= 0 && irq < RP2040_NUM_IRQS);
-    s->irq_level[irq] = level;
+    s->irq_level[0][irq] = level;
+    s->irq_level[1][irq] = level;
+    rp2040_update_nmi(s);
+}
+
+static void rp2040_set_core0_irq(void *opaque, int irq, int level)
+{
+    RP2040State *s = opaque;
+
+    assert(irq >= 0 && irq < RP2040_NUM_IRQS);
+    s->irq_level[0][irq] = level;
+    rp2040_update_nmi(s);
+}
+
+static void rp2040_set_core1_irq(void *opaque, int irq, int level)
+{
+    RP2040State *s = opaque;
+
+    assert(irq >= 0 && irq < RP2040_NUM_IRQS);
+    s->irq_level[1][irq] = level;
     rp2040_update_nmi(s);
 }
 
@@ -1671,6 +1691,10 @@ static void rp2040_soc_init(Object *obj)
     object_initialize_child(obj, "xosc", &s->xosc, TYPE_RP2040_XOSC);
 
     s->irq = qemu_allocate_irqs(rp2040_set_irq, s, RP2040_NUM_IRQS);
+    s->core_irq[0] = qemu_allocate_irqs(rp2040_set_core0_irq, s,
+                                        RP2040_NUM_IRQS);
+    s->core_irq[1] = qemu_allocate_irqs(rp2040_set_core1_irq, s,
+                                        RP2040_NUM_IRQS);
 
     s->sysclk = clock_new(obj, "sysclk");
 }
@@ -1882,7 +1906,7 @@ static void rp2040_soc_realize(DeviceState *dev, Error 
**errp)
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->sio), 0, RP2040_SIO_BASE);
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sio), 0,
-                       s->irq[RP2040_SIO_IRQ_PROC0]);
+                       s->core_irq[0][RP2040_SIO_IRQ_PROC0]);
 
     for (i = 0; i < RP2040_NUM_CORES; i++) {
         g_autofree char *memory_name =
@@ -1938,9 +1962,9 @@ static void rp2040_soc_realize(DeviceState *dev, Error 
**errp)
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->iobank0), 0, RP2040_IOBANK0_BASE);
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->iobank0), 0,
-                       s->irq[RP2040_IO_IRQ_BANK0]);
+                       s->core_irq[0][RP2040_IO_IRQ_BANK0]);
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->iobank0), 1,
-                       s->cpu_irq[RP2040_PROC1][RP2040_IO_IRQ_BANK0]);
+                       s->core_irq[1][RP2040_IO_IRQ_BANK0]);
     qdev_connect_gpio_out_named(DEVICE(&s->iobank0), "uart0-pin", 0,
                                 qdev_get_gpio_in_named(dev, "uart-pin", 0));
     qdev_connect_gpio_out_named(DEVICE(&s->iobank0), "uart0-pin", 1,
@@ -1950,7 +1974,7 @@ static void rp2040_soc_realize(DeviceState *dev, Error 
**errp)
     qdev_connect_gpio_out_named(DEVICE(&s->iobank0), "uart1-pin", 1,
                                 qdev_get_gpio_in_named(dev, "uart-pin", 3));
     sysbus_connect_irq(SYS_BUS_DEVICE(&s->sio), 1,
-                       s->cpu_irq[RP2040_PROC1][RP2040_SIO_IRQ_PROC1]);
+                       s->core_irq[1][RP2040_SIO_IRQ_PROC1]);
 
     object_property_set_link(OBJECT(&s->ioqspi), "xip", OBJECT(&s->xip),
                              &err);
@@ -1962,6 +1986,10 @@ static void rp2040_soc_realize(DeviceState *dev, Error 
**errp)
         return;
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioqspi), 0, RP2040_IOQSPI_BASE);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioqspi), 0,
+                       s->core_irq[0][RP2040_IO_IRQ_QSPI]);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioqspi), 1,
+                       s->core_irq[1][RP2040_IO_IRQ_QSPI]);
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->rosc), errp)) {
         return;
diff --git a/hw/misc/rp2040_ioqspi.c b/hw/misc/rp2040_ioqspi.c
index d8fd98934c..59ff24e32b 100644
--- a/hw/misc/rp2040_ioqspi.c
+++ b/hw/misc/rp2040_ioqspi.c
@@ -54,6 +54,16 @@ static uint32_t rp2040_ioqspi_ints(uint32_t intr, uint32_t 
inte,
     return (intr & inte) | intf;
 }
 
+static void rp2040_ioqspi_update_irq(RP2040IoQspiState *s)
+{
+    qemu_set_irq(s->proc0_irq,
+                 rp2040_ioqspi_ints(s->intr, s->proc0_inte,
+                                    s->proc0_intf) != 0);
+    qemu_set_irq(s->proc1_irq,
+                 rp2040_ioqspi_ints(s->intr, s->proc1_inte,
+                                    s->proc1_intf) != 0);
+}
+
 static void rp2040_ioqspi_update_ss(RP2040IoQspiState *s)
 {
     uint32_t outover;
@@ -148,26 +158,31 @@ static void rp2040_ioqspi_write(void *opaque, hwaddr addr,
         switch (offset) {
         case IOQSPI_INTR:
             s->intr &= ~(value & IOQSPI_INTR_EDGE_MASK);
+            rp2040_ioqspi_update_irq(s);
             break;
         case IOQSPI_PROC0_INTE:
             s->proc0_inte =
                 rp2040_atomic_update(s->proc0_inte, value, alias) &
                 IOQSPI_IRQ_MASK;
+            rp2040_ioqspi_update_irq(s);
             break;
         case IOQSPI_PROC0_INTF:
             s->proc0_intf =
                 rp2040_atomic_update(s->proc0_intf, value, alias) &
                 IOQSPI_IRQ_MASK;
+            rp2040_ioqspi_update_irq(s);
             break;
         case IOQSPI_PROC1_INTE:
             s->proc1_inte =
                 rp2040_atomic_update(s->proc1_inte, value, alias) &
                 IOQSPI_IRQ_MASK;
+            rp2040_ioqspi_update_irq(s);
             break;
         case IOQSPI_PROC1_INTF:
             s->proc1_intf =
                 rp2040_atomic_update(s->proc1_intf, value, alias) &
                 IOQSPI_IRQ_MASK;
+            rp2040_ioqspi_update_irq(s);
             break;
         case IOQSPI_DORMANT_INTE:
             s->dormant_wake_inte =
@@ -222,6 +237,7 @@ static void rp2040_ioqspi_reset(DeviceState *dev)
     s->proc1_intf = 0;
     s->dormant_wake_inte = 0;
     s->dormant_wake_intf = 0;
+    rp2040_ioqspi_update_irq(s);
 }
 
 static void rp2040_ioqspi_init(Object *obj)
@@ -231,6 +247,8 @@ static void rp2040_ioqspi_init(Object *obj)
     memory_region_init_io(&s->iomem, obj, &rp2040_ioqspi_ops, s,
                           "rp2040.ioqspi", RP2040_IOQSPI_SIZE);
     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->proc0_irq);
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->proc1_irq);
 }
 
 static const VMStateDescription rp2040_ioqspi_vmstate = {
diff --git a/include/hw/arm/rp2040.h b/include/hw/arm/rp2040.h
index 498d36dd5c..2d9a0abc88 100644
--- a/include/hw/arm/rp2040.h
+++ b/include/hw/arm/rp2040.h
@@ -103,9 +103,10 @@ struct RP2040State {
     char *bootrom_file;
 
     qemu_irq *irq;
+    qemu_irq *core_irq[RP2040_NUM_CORES];
     qemu_irq cpu_irq[RP2040_NUM_CORES][RP2040_NUM_IRQS];
     qemu_irq nmi_irq[RP2040_NUM_CORES];
-    bool irq_level[RP2040_NUM_IRQS];
+    bool irq_level[RP2040_NUM_CORES][RP2040_NUM_IRQS];
     bool strict_uart_pins;
     bool uart0_tx_pin_enabled;
     bool uart0_rx_pin_enabled;
diff --git a/include/hw/misc/rp2040_ioqspi.h b/include/hw/misc/rp2040_ioqspi.h
index eae63588e6..0ab8acfbf0 100644
--- a/include/hw/misc/rp2040_ioqspi.h
+++ b/include/hw/misc/rp2040_ioqspi.h
@@ -30,6 +30,8 @@ struct RP2040IoQspiState {
     uint32_t proc1_intf;
     uint32_t dormant_wake_inte;
     uint32_t dormant_wake_intf;
+    qemu_irq proc0_irq;
+    qemu_irq proc1_irq;
     RP2040XipState *xip;
 };
 
diff --git a/tests/qtest/rp2040-ioqspi-test.c b/tests/qtest/rp2040-ioqspi-test.c
index 4f94b5f3a2..31dd85686f 100644
--- a/tests/qtest/rp2040-ioqspi-test.c
+++ b/tests/qtest/rp2040-ioqspi-test.c
@@ -15,6 +15,8 @@
 #define IOQSPI_PROC0_INTE       0x34
 #define IOQSPI_PROC0_INTF       0x38
 #define IOQSPI_PROC0_INTS       0x3c
+#define IOQSPI_PROC1_INTF       0x44
+#define IOQSPI_PROC1_INTS       0x48
 
 #define IOQSPI_CTRL_RESET       0x1f
 #define IOQSPI_SD1_CTRL_SET     0x201c
@@ -58,11 +60,31 @@ static void test_ioqspi_interrupt_force_status(void)
 {
     QTestState *qts = rp2040_start();
 
+    qtest_irq_intercept_in(qts, "/machine/soc/proc0");
+    g_assert_false(qtest_get_irq(qts, 14));
+
     qtest_writel(qts, IOQSPI_BASE + IOQSPI_PROC0_INTE, BIT(1));
     qtest_writel(qts, IOQSPI_BASE + IOQSPI_PROC0_INTF, BIT(2));
 
     g_assert_cmphex(qtest_readl(qts, IOQSPI_BASE + IOQSPI_PROC0_INTS), ==,
                     BIT(2));
+    g_assert_true(qtest_get_irq(qts, 14));
+    qtest_writel(qts, IOQSPI_BASE + IOQSPI_PROC0_INTF + 0x3000, BIT(2));
+    g_assert_false(qtest_get_irq(qts, 14));
+
+    qtest_quit(qts);
+    qts = rp2040_start();
+
+    qtest_irq_intercept_in(qts, "/machine/soc/proc1");
+    g_assert_false(qtest_get_irq(qts, 14));
+
+    qtest_writel(qts, IOQSPI_BASE + IOQSPI_PROC1_INTF, BIT(3));
+    g_assert_cmphex(qtest_readl(qts, IOQSPI_BASE + IOQSPI_PROC1_INTS), ==,
+                    BIT(3));
+    g_assert_true(qtest_get_irq(qts, 14));
+
+    qtest_writel(qts, IOQSPI_BASE + IOQSPI_PROC1_INTF + 0x3000, BIT(3));
+    g_assert_false(qtest_get_irq(qts, 14));
 
     qtest_quit(qts);
 }
-- 
2.55.0


Reply via email to