All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] hw/ppc: Convert UIC device to QOM
@ 2020-12-12  0:15 Peter Maydell
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
                   ` (9 more replies)
  0 siblings, 10 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

This patchseries converts the PPC UIC "Universal Interrupt
Controller" to a QOM device.  My main reason for doing it is that
this fixes a couple of long-standing trivial Coverity issues -- the
current ppcuic_init() function allocates an array of qemu_irqs which
the callers then leak.  (The leak is trivial because it happens once
when QEMU starts.)

The patchseries converts the UIC to a QOM device but initially leaves
the old ppcuic_init() creation function with its old API intact.  It
then goes through converting the various boards that were using
ppcuic_init() to instead directly create the UIC using the usual qdev
APIs, so that it can delete the ppcuic_init() function entirely.

The patchset includes one patch which deletes 350 lines of dead code
-- the ppc405cr_init() function seems to have never been used since
it was added in 2007, so rather than converting this user of
ppcuic_init() it seemed more sensible to delete it.

I have tested with 'make check' and 'make check-acceptance' but I
don't think the latter really exercises the affected boards, which
are:

 bamboo
 ref405ep
 sam460ex
 taihu
 virtex-ml507

I found instructions on how to boot an AROS image on sam460ex, so I
have tested that: it works as well after this series as it did before
(gets to "Libs/workbench.library" and stops); it does seem to
successfully do things like scanning the USB bus and responding to
keyboard input at the boot menu, which suggests that IRQs must be
working.

Side note: the 'irq_inputs' hacks in the PPC CPU I think would really
benefit from conversion to being qdev gpio inputs now that CPUs are
real devices. There are also a lot of non-QOM devices in this
ppc4xx code if anybody is interested in working on more QOM
conversions for these boards.

thanks
-- PMM

Peter Maydell (8):
  hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  ppc: Convert PPC UIC to a QOM device
  hw/ppc/virtex_ml507: Drop use of ppcuic_init()
  hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  hw/ppc/sam460ex: Drop use of ppcuic_init()
  hw/ppc: Delete unused ppc405cr_init() code
  hw/ppc/ppc405_uc: Drop use of ppcuic_init()
  hw/ppc: Remove unused ppcuic_init()

 hw/ppc/ppc405.h           |   8 +-
 include/hw/intc/ppc-uic.h |  80 ++++++++
 include/hw/ppc/ppc4xx.h   |   9 -
 hw/intc/ppc-uic.c         | 321 +++++++++++++++++++++++++++++
 hw/ppc/ppc405_boards.c    |   8 +-
 hw/ppc/ppc405_uc.c        | 415 ++++----------------------------------
 hw/ppc/ppc440_bamboo.c    |  38 +++-
 hw/ppc/ppc4xx_devs.c      | 246 +---------------------
 hw/ppc/sam460ex.c         |  70 +++++--
 hw/ppc/virtex_ml507.c     |  21 +-
 MAINTAINERS               |   2 +
 hw/intc/Kconfig           |   3 +
 hw/intc/meson.build       |   1 +
 hw/ppc/Kconfig            |   1 +
 14 files changed, 555 insertions(+), 668 deletions(-)
 create mode 100644 include/hw/intc/ppc-uic.h
 create mode 100644 hw/intc/ppc-uic.c

-- 
2.20.1



^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-13 12:09   ` Philippe Mathieu-Daudé
                     ` (3 more replies)
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
                   ` (8 subsequent siblings)
  9 siblings, 4 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

In a following commit we will move the PPC UIC implementation to
its own file in hw/intc. To prevent checkpatch complaining about that
code-motion, fix up the minor style issues first.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/ppc4xx_devs.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index f1651e04d9a..f2f9ca4ffec 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -105,7 +105,7 @@ struct ppcuic_t {
     qemu_irq *irqs;
 };
 
-static void ppcuic_trigger_irq (ppcuic_t *uic)
+static void ppcuic_trigger_irq(ppcuic_t *uic)
 {
     uint32_t ir, cr;
     int start, end, inc, i;
@@ -156,26 +156,28 @@ static void ppcuic_trigger_irq (ppcuic_t *uic)
     }
 }
 
-static void ppcuic_set_irq (void *opaque, int irq_num, int level)
+static void ppcuic_set_irq(void *opaque, int irq_num, int level)
 {
     ppcuic_t *uic;
     uint32_t mask, sr;
 
     uic = opaque;
-    mask = 1U << (31-irq_num);
+    mask = 1U << (31 - irq_num);
     LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
                 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
                 __func__, irq_num, level,
                 uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
-    if (irq_num < 0 || irq_num > 31)
+    if (irq_num < 0 || irq_num > 31) {
         return;
+    }
     sr = uic->uicsr;
 
     /* Update status register */
     if (uic->uictr & mask) {
         /* Edge sensitive interrupt */
-        if (level == 1)
+        if (level == 1) {
             uic->uicsr |= mask;
+        }
     } else {
         /* Level sensitive interrupt */
         if (level == 1) {
@@ -188,11 +190,12 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level)
     }
     LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
                 "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
-    if (sr != uic->uicsr)
+    if (sr != uic->uicsr) {
         ppcuic_trigger_irq(uic);
+    }
 }
 
-static uint32_t dcr_read_uic (void *opaque, int dcrn)
+static uint32_t dcr_read_uic(void *opaque, int dcrn)
 {
     ppcuic_t *uic;
     uint32_t ret;
@@ -220,13 +223,15 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
         ret = uic->uicsr & uic->uicer;
         break;
     case DCR_UICVR:
-        if (!uic->use_vectors)
+        if (!uic->use_vectors) {
             goto no_read;
+        }
         ret = uic->uicvr;
         break;
     case DCR_UICVCR:
-        if (!uic->use_vectors)
+        if (!uic->use_vectors) {
             goto no_read;
+        }
         ret = uic->uicvcr;
         break;
     default:
@@ -238,7 +243,7 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
     return ret;
 }
 
-static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
+static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
 {
     ppcuic_t *uic;
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-12 16:57   ` BALATON Zoltan via
                     ` (4 more replies)
  2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
                   ` (7 subsequent siblings)
  9 siblings, 5 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Currently the PPC UIC ("Universal Interrupt Controller") is implemented
as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
in hw/intc.

The ppcuic_init() function is retained for the moment with its current
interface; in subsequent commits this will be tidied up to avoid the
allocation of an irq array.

This conversion adds VMState support.

It leaves the LOG_UIC() macro as-is to maximise the extent to which
this is simply code-movement rather than a rewrite (in new code it
would be better to use tracepoints).

The default property values for dcr-base and use-vectors are set to
match those use by most of our boards with a UIC.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/intc/ppc-uic.h |  73 +++++++++
 hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
 hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
 MAINTAINERS               |   2 +
 hw/intc/Kconfig           |   3 +
 hw/intc/meson.build       |   1 +
 hw/ppc/Kconfig            |   1 +
 7 files changed, 431 insertions(+), 237 deletions(-)
 create mode 100644 include/hw/intc/ppc-uic.h
 create mode 100644 hw/intc/ppc-uic.c

diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
new file mode 100644
index 00000000000..e614e2ffd80
--- /dev/null
+++ b/include/hw/intc/ppc-uic.h
@@ -0,0 +1,73 @@
+/*
+ * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_INTC_PPC_UIC_H
+#define HW_INTC_PPC_UIC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_PPC_UIC "ppc-uic"
+OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
+
+/*
+ * QEMU interface:
+ * QOM property "cpu": link to the PPC CPU
+ *    (no default, must be set)
+ * QOM property "dcr-base": base of the bank of DCR registers for the UIC
+ *    (default 0x30)
+ * QOM property "use-vectors": true if the UIC has vector registers
+ *    (default true)
+ * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
+ * sysbus IRQs:
+ *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
+ *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
+ */
+
+#define UIC_MAX_IRQ 32
+
+struct PPCUIC {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    qemu_irq output_int;
+    qemu_irq output_cint;
+
+    /* properties */
+    CPUState *cpu;
+    uint32_t dcr_base;
+    bool use_vectors;
+
+    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
+    uint32_t uicsr;  /* Status register */
+    uint32_t uicer;  /* Enable register */
+    uint32_t uiccr;  /* Critical register */
+    uint32_t uicpr;  /* Polarity register */
+    uint32_t uictr;  /* Triggering register */
+    uint32_t uicvcr; /* Vector configuration register */
+    uint32_t uicvr;
+};
+
+#endif
diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
new file mode 100644
index 00000000000..b21951eea83
--- /dev/null
+++ b/hw/intc/ppc-uic.c
@@ -0,0 +1,321 @@
+/*
+ * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "include/hw/intc/ppc-uic.h"
+#include "hw/irq.h"
+#include "cpu.h"
+#include "hw/ppc/ppc.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+
+enum {
+    DCR_UICSR  = 0x000,
+    DCR_UICSRS = 0x001,
+    DCR_UICER  = 0x002,
+    DCR_UICCR  = 0x003,
+    DCR_UICPR  = 0x004,
+    DCR_UICTR  = 0x005,
+    DCR_UICMSR = 0x006,
+    DCR_UICVR  = 0x007,
+    DCR_UICVCR = 0x008,
+    DCR_UICMAX = 0x009,
+};
+
+/*#define DEBUG_UIC*/
+
+#ifdef DEBUG_UIC
+#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
+#else
+#  define LOG_UIC(...) do { } while (0)
+#endif
+
+static void ppcuic_trigger_irq(PPCUIC *uic)
+{
+    uint32_t ir, cr;
+    int start, end, inc, i;
+
+    /* Trigger interrupt if any is pending */
+    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
+    cr = uic->uicsr & uic->uicer & uic->uiccr;
+    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
+                " uiccr %08" PRIx32 "\n"
+                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
+                __func__, uic->uicsr, uic->uicer, uic->uiccr,
+                uic->uicsr & uic->uicer, ir, cr);
+    if (ir != 0x0000000) {
+        LOG_UIC("Raise UIC interrupt\n");
+        qemu_irq_raise(uic->output_int);
+    } else {
+        LOG_UIC("Lower UIC interrupt\n");
+        qemu_irq_lower(uic->output_int);
+    }
+    /* Trigger critical interrupt if any is pending and update vector */
+    if (cr != 0x0000000) {
+        qemu_irq_raise(uic->output_cint);
+        if (uic->use_vectors) {
+            /* Compute critical IRQ vector */
+            if (uic->uicvcr & 1) {
+                start = 31;
+                end = 0;
+                inc = -1;
+            } else {
+                start = 0;
+                end = 31;
+                inc = 1;
+            }
+            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
+            for (i = start; i <= end; i += inc) {
+                if (cr & (1 << i)) {
+                    uic->uicvr += (i - start) * 512 * inc;
+                    break;
+                }
+            }
+        }
+        LOG_UIC("Raise UIC critical interrupt - "
+                    "vector %08" PRIx32 "\n", uic->uicvr);
+    } else {
+        LOG_UIC("Lower UIC critical interrupt\n");
+        qemu_irq_lower(uic->output_cint);
+        uic->uicvr = 0x00000000;
+    }
+}
+
+static void ppcuic_set_irq(void *opaque, int irq_num, int level)
+{
+    PPCUIC *uic;
+    uint32_t mask, sr;
+
+    uic = opaque;
+    mask = 1U << (31 - irq_num);
+    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
+                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
+                __func__, irq_num, level,
+                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
+    if (irq_num < 0 || irq_num > 31) {
+        return;
+    }
+    sr = uic->uicsr;
+
+    /* Update status register */
+    if (uic->uictr & mask) {
+        /* Edge sensitive interrupt */
+        if (level == 1) {
+            uic->uicsr |= mask;
+        }
+    } else {
+        /* Level sensitive interrupt */
+        if (level == 1) {
+            uic->uicsr |= mask;
+            uic->level |= mask;
+        } else {
+            uic->uicsr &= ~mask;
+            uic->level &= ~mask;
+        }
+    }
+    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
+                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
+    if (sr != uic->uicsr) {
+        ppcuic_trigger_irq(uic);
+    }
+}
+
+static uint32_t dcr_read_uic(void *opaque, int dcrn)
+{
+    PPCUIC *uic;
+    uint32_t ret;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    switch (dcrn) {
+    case DCR_UICSR:
+    case DCR_UICSRS:
+        ret = uic->uicsr;
+        break;
+    case DCR_UICER:
+        ret = uic->uicer;
+        break;
+    case DCR_UICCR:
+        ret = uic->uiccr;
+        break;
+    case DCR_UICPR:
+        ret = uic->uicpr;
+        break;
+    case DCR_UICTR:
+        ret = uic->uictr;
+        break;
+    case DCR_UICMSR:
+        ret = uic->uicsr & uic->uicer;
+        break;
+    case DCR_UICVR:
+        if (!uic->use_vectors) {
+            goto no_read;
+        }
+        ret = uic->uicvr;
+        break;
+    case DCR_UICVCR:
+        if (!uic->use_vectors) {
+            goto no_read;
+        }
+        ret = uic->uicvcr;
+        break;
+    default:
+    no_read:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
+{
+    PPCUIC *uic;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
+    switch (dcrn) {
+    case DCR_UICSR:
+        uic->uicsr &= ~val;
+        uic->uicsr |= uic->level;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICSRS:
+        uic->uicsr |= val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICER:
+        uic->uicer = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICCR:
+        uic->uiccr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICPR:
+        uic->uicpr = val;
+        break;
+    case DCR_UICTR:
+        uic->uictr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICMSR:
+        break;
+    case DCR_UICVR:
+        break;
+    case DCR_UICVCR:
+        uic->uicvcr = val & 0xFFFFFFFD;
+        ppcuic_trigger_irq(uic);
+        break;
+    }
+}
+
+static void ppc_uic_reset(DeviceState *dev)
+{
+    PPCUIC *uic = PPC_UIC(dev);
+
+    uic->uiccr = 0x00000000;
+    uic->uicer = 0x00000000;
+    uic->uicpr = 0x00000000;
+    uic->uicsr = 0x00000000;
+    uic->uictr = 0x00000000;
+    if (uic->use_vectors) {
+        uic->uicvcr = 0x00000000;
+        uic->uicvr = 0x0000000;
+    }
+}
+
+static void ppc_uic_realize(DeviceState *dev, Error **errp)
+{
+    PPCUIC *uic = PPC_UIC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    PowerPCCPU *cpu;
+    int i;
+
+    if (!uic->cpu) {
+        /* This is a programming error in the code using this device */
+        error_setg(errp, "ppc-uic 'cpu' link property was not set");
+        return;
+    }
+
+    cpu = POWERPC_CPU(uic->cpu);
+    for (i = 0; i < DCR_UICMAX; i++) {
+        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
+                         &dcr_read_uic, &dcr_write_uic);
+    }
+
+    sysbus_init_irq(sbd, &uic->output_int);
+    sysbus_init_irq(sbd, &uic->output_cint);
+    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
+}
+
+static Property ppc_uic_properties[] = {
+    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
+    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
+    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription ppc_uic_vmstate = {
+    .name = "ppc-uic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, PPCUIC),
+        VMSTATE_UINT32(uicsr, PPCUIC),
+        VMSTATE_UINT32(uicer, PPCUIC),
+        VMSTATE_UINT32(uiccr, PPCUIC),
+        VMSTATE_UINT32(uicpr, PPCUIC),
+        VMSTATE_UINT32(uictr, PPCUIC),
+        VMSTATE_UINT32(uicvcr, PPCUIC),
+        VMSTATE_UINT32(uicvr, PPCUIC),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void ppc_uic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = ppc_uic_reset;
+    dc->realize = ppc_uic_realize;
+    dc->vmsd = &ppc_uic_vmstate;
+    device_class_set_props(dc, ppc_uic_properties);
+}
+
+static const TypeInfo ppc_uic_info = {
+    .name = TYPE_PPC_UIC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PPCUIC),
+    .class_init = ppc_uic_class_init,
+};
+
+static void ppc_uic_register_types(void)
+{
+    type_register_static(&ppc_uic_info);
+}
+
+type_init(ppc_uic_register_types);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index f2f9ca4ffec..ffe4cf43e88 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -30,9 +30,12 @@
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/ppc4xx.h"
 #include "hw/boards.h"
+#include "hw/intc/ppc-uic.h"
+#include "hw/qdev-properties.h"
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 
 /*#define DEBUG_UIC*/
 
@@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
 
 /*****************************************************************************/
 /* "Universal" Interrupt controller */
-enum {
-    DCR_UICSR  = 0x000,
-    DCR_UICSRS = 0x001,
-    DCR_UICER  = 0x002,
-    DCR_UICCR  = 0x003,
-    DCR_UICPR  = 0x004,
-    DCR_UICTR  = 0x005,
-    DCR_UICMSR = 0x006,
-    DCR_UICVR  = 0x007,
-    DCR_UICVCR = 0x008,
-    DCR_UICMAX = 0x009,
-};
-
-#define UIC_MAX_IRQ 32
-typedef struct ppcuic_t ppcuic_t;
-struct ppcuic_t {
-    uint32_t dcr_base;
-    int use_vectors;
-    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
-    uint32_t uicsr;  /* Status register */
-    uint32_t uicer;  /* Enable register */
-    uint32_t uiccr;  /* Critical register */
-    uint32_t uicpr;  /* Polarity register */
-    uint32_t uictr;  /* Triggering register */
-    uint32_t uicvcr; /* Vector configuration register */
-    uint32_t uicvr;
-    qemu_irq *irqs;
-};
-
-static void ppcuic_trigger_irq(ppcuic_t *uic)
-{
-    uint32_t ir, cr;
-    int start, end, inc, i;
-
-    /* Trigger interrupt if any is pending */
-    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
-    cr = uic->uicsr & uic->uicer & uic->uiccr;
-    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
-                " uiccr %08" PRIx32 "\n"
-                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
-                __func__, uic->uicsr, uic->uicer, uic->uiccr,
-                uic->uicsr & uic->uicer, ir, cr);
-    if (ir != 0x0000000) {
-        LOG_UIC("Raise UIC interrupt\n");
-        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
-    } else {
-        LOG_UIC("Lower UIC interrupt\n");
-        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
-    }
-    /* Trigger critical interrupt if any is pending and update vector */
-    if (cr != 0x0000000) {
-        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
-        if (uic->use_vectors) {
-            /* Compute critical IRQ vector */
-            if (uic->uicvcr & 1) {
-                start = 31;
-                end = 0;
-                inc = -1;
-            } else {
-                start = 0;
-                end = 31;
-                inc = 1;
-            }
-            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
-            for (i = start; i <= end; i += inc) {
-                if (cr & (1 << i)) {
-                    uic->uicvr += (i - start) * 512 * inc;
-                    break;
-                }
-            }
-        }
-        LOG_UIC("Raise UIC critical interrupt - "
-                    "vector %08" PRIx32 "\n", uic->uicvr);
-    } else {
-        LOG_UIC("Lower UIC critical interrupt\n");
-        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
-        uic->uicvr = 0x00000000;
-    }
-}
-
-static void ppcuic_set_irq(void *opaque, int irq_num, int level)
-{
-    ppcuic_t *uic;
-    uint32_t mask, sr;
-
-    uic = opaque;
-    mask = 1U << (31 - irq_num);
-    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
-                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
-                __func__, irq_num, level,
-                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
-    if (irq_num < 0 || irq_num > 31) {
-        return;
-    }
-    sr = uic->uicsr;
-
-    /* Update status register */
-    if (uic->uictr & mask) {
-        /* Edge sensitive interrupt */
-        if (level == 1) {
-            uic->uicsr |= mask;
-        }
-    } else {
-        /* Level sensitive interrupt */
-        if (level == 1) {
-            uic->uicsr |= mask;
-            uic->level |= mask;
-        } else {
-            uic->uicsr &= ~mask;
-            uic->level &= ~mask;
-        }
-    }
-    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
-                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
-    if (sr != uic->uicsr) {
-        ppcuic_trigger_irq(uic);
-    }
-}
-
-static uint32_t dcr_read_uic(void *opaque, int dcrn)
-{
-    ppcuic_t *uic;
-    uint32_t ret;
-
-    uic = opaque;
-    dcrn -= uic->dcr_base;
-    switch (dcrn) {
-    case DCR_UICSR:
-    case DCR_UICSRS:
-        ret = uic->uicsr;
-        break;
-    case DCR_UICER:
-        ret = uic->uicer;
-        break;
-    case DCR_UICCR:
-        ret = uic->uiccr;
-        break;
-    case DCR_UICPR:
-        ret = uic->uicpr;
-        break;
-    case DCR_UICTR:
-        ret = uic->uictr;
-        break;
-    case DCR_UICMSR:
-        ret = uic->uicsr & uic->uicer;
-        break;
-    case DCR_UICVR:
-        if (!uic->use_vectors) {
-            goto no_read;
-        }
-        ret = uic->uicvr;
-        break;
-    case DCR_UICVCR:
-        if (!uic->use_vectors) {
-            goto no_read;
-        }
-        ret = uic->uicvcr;
-        break;
-    default:
-    no_read:
-        ret = 0x00000000;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
-{
-    ppcuic_t *uic;
-
-    uic = opaque;
-    dcrn -= uic->dcr_base;
-    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
-    switch (dcrn) {
-    case DCR_UICSR:
-        uic->uicsr &= ~val;
-        uic->uicsr |= uic->level;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICSRS:
-        uic->uicsr |= val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICER:
-        uic->uicer = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICCR:
-        uic->uiccr = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICPR:
-        uic->uicpr = val;
-        break;
-    case DCR_UICTR:
-        uic->uictr = val;
-        ppcuic_trigger_irq(uic);
-        break;
-    case DCR_UICMSR:
-        break;
-    case DCR_UICVR:
-        break;
-    case DCR_UICVCR:
-        uic->uicvcr = val & 0xFFFFFFFD;
-        ppcuic_trigger_irq(uic);
-        break;
-    }
-}
-
-static void ppcuic_reset (void *opaque)
-{
-    ppcuic_t *uic;
-
-    uic = opaque;
-    uic->uiccr = 0x00000000;
-    uic->uicer = 0x00000000;
-    uic->uicpr = 0x00000000;
-    uic->uicsr = 0x00000000;
-    uic->uictr = 0x00000000;
-    if (uic->use_vectors) {
-        uic->uicvcr = 0x00000000;
-        uic->uicvr = 0x0000000;
-    }
-}
 
 qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
                        uint32_t dcr_base, int has_ssr, int has_vr)
 {
-    ppcuic_t *uic;
+    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
+    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
+    qemu_irq *uic_irqs;
     int i;
 
-    uic = g_malloc0(sizeof(ppcuic_t));
-    uic->dcr_base = dcr_base;
-    uic->irqs = irqs;
-    if (has_vr)
-        uic->use_vectors = 1;
-    for (i = 0; i < DCR_UICMAX; i++) {
-        ppc_dcr_register(env, dcr_base + i, uic,
-                         &dcr_read_uic, &dcr_write_uic);
-    }
-    qemu_register_reset(ppcuic_reset, uic);
+    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
+    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
+    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
+                             &error_fatal);
+    sysbus_realize_and_unref(uicsbd, &error_fatal);
 
-    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
+
+    /*
+     * Return an allocated array of the UIC's input IRQ lines.
+     * This is an ugly temporary API to retain compatibility with
+     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
+     * None of the callers free this array, so it is leaked -- but
+     * so was the array allocated by qemu_allocate_irqs() in the
+     * old code.
+     *
+     * The callers should just instantiate the UIC and wire it up
+     * themselves rather than passing qemu_irq* in and out of this function.
+     */
+    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
+    for (i = 0; i < UIC_MAX_IRQ; i++) {
+        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
+    }
+    return uic_irqs;
 }
 
 /*****************************************************************************/
diff --git a/MAINTAINERS b/MAINTAINERS
index aa39490a244..24218800b16 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
 F: hw/i2c/ppc4xx_i2c.c
 F: include/hw/ppc/ppc4xx.h
 F: include/hw/i2c/ppc4xx_i2c.h
+F: hw/intc/ppc-uic.c
+F: include/hw/intc/ppc-uic.h
 
 Character devices
 M: Marc-André Lureau <marcandre.lureau@redhat.com>
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index d07954086a5..468d548ca77 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -62,6 +62,9 @@ config S390_FLIC_KVM
 config OMPIC
     bool
 
+config PPC_UIC
+    bool
+
 config RX_ICU
     bool
 
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 3f82cc230ad..d7dadbe5034 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
 specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
 specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
 specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
+specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
 specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
 specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
 specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index dd86e664d21..982d55f5875 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -53,6 +53,7 @@ config PPC4XX
     bool
     select BITBANG_I2C
     select PCI
+    select PPC_UIC
 
 config SAM460EX
     bool
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init()
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-13 14:32   ` Edgar E. Iglesias
                     ` (2 more replies)
  2020-12-12  0:15 ` [PATCH 4/8] hw/ppc/ppc440_bamboo: " Peter Maydell
                   ` (6 subsequent siblings)
  9 siblings, 3 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Switch the virtex_ml507 board to directly creating and
configuring the UIC, rather than doing it via the old
ppcuic_init() helper function.

This fixes a trivial Coverity-detected memory leak where
we were leaking the array of IRQs returned by ppcuic_init().

Fixes: Coverity CID 1421992
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/virtex_ml507.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 7f1bca928c1..34767b11cad 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -43,6 +43,7 @@
 #include "qemu/option.h"
 #include "exec/address-spaces.h"
 
+#include "hw/intc/ppc-uic.h"
 #include "hw/ppc/ppc.h"
 #include "hw/ppc/ppc4xx.h"
 #include "hw/qdev-properties.h"
@@ -95,7 +96,8 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
 {
     PowerPCCPU *cpu;
     CPUPPCState *env;
-    qemu_irq *irqs;
+    DeviceState *uicdev;
+    SysBusDevice *uicsbd;
 
     cpu = POWERPC_CPU(cpu_create(cpu_type));
     env = &cpu->env;
@@ -105,10 +107,19 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
     ppc_dcr_init(env, NULL, NULL);
 
     /* interrupt controller */
-    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    uicdev = qdev_new(TYPE_PPC_UIC);
+    uicsbd = SYS_BUS_DEVICE(uicdev);
+
+    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
+                             &error_fatal);
+    sysbus_realize_and_unref(uicsbd, &error_fatal);
+
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
+
+    /* This board doesn't wire anything up to the inputs of the UIC. */
     return cpu;
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (2 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-14  5:56   ` David Gibson
  2021-01-11  1:00   ` Nathan Chancellor
  2020-12-12  0:15 ` [PATCH 5/8] hw/ppc/sam460ex: " Peter Maydell
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Switch the bamboo board to directly creating and configuring the UIC,
rather than doing it via the old ppcuic_init() helper function.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/ppc440_bamboo.c | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 665bc1784e1..b156bcb9990 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -33,6 +33,9 @@
 #include "sysemu/qtest.h"
 #include "sysemu/reset.h"
 #include "hw/sysbus.h"
+#include "hw/intc/ppc-uic.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -168,13 +171,13 @@ static void bamboo_init(MachineState *machine)
     MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
     hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
     hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
-    qemu_irq *pic;
-    qemu_irq *irqs;
     PCIBus *pcibus;
     PowerPCCPU *cpu;
     CPUPPCState *env;
     target_long initrd_size = 0;
     DeviceState *dev;
+    DeviceState *uicdev;
+    SysBusDevice *uicsbd;
     int success;
     int i;
 
@@ -192,10 +195,17 @@ static void bamboo_init(MachineState *machine)
     ppc_dcr_init(env, NULL, NULL);
 
     /* interrupt controller */
-    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    uicdev = qdev_new(TYPE_PPC_UIC);
+    uicsbd = SYS_BUS_DEVICE(uicdev);
+
+    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
+                             &error_fatal);
+    sysbus_realize_and_unref(uicsbd, &error_fatal);
+
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
 
     /* SDRAM controller */
     memset(ram_bases, 0, sizeof(ram_bases));
@@ -203,14 +213,18 @@ static void bamboo_init(MachineState *machine)
     ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories,
                        ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes);
     /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
-    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+    ppc4xx_sdram_init(env,
+                      qdev_get_gpio_in(uicdev, 14),
+                      PPC440EP_SDRAM_NR_BANKS, ram_memories,
                       ram_bases, ram_sizes, 1);
 
     /* PCI */
     dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
                                 PPC440EP_PCI_CONFIG,
-                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
-                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
+                                qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
+                                qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
+                                qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
+                                qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
                                 NULL);
     pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
     if (!pcibus) {
@@ -223,12 +237,14 @@ static void bamboo_init(MachineState *machine)
     memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
 
     if (serial_hd(0) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+        serial_mm_init(address_space_mem, 0xef600300, 0,
+                       qdev_get_gpio_in(uicdev, 0),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hd(1) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+        serial_mm_init(address_space_mem, 0xef600400, 0,
+                       qdev_get_gpio_in(uicdev, 1),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
                        DEVICE_BIG_ENDIAN);
     }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (3 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 4/8] hw/ppc/ppc440_bamboo: " Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-12 17:17   ` BALATON Zoltan via
  2020-12-12 19:53   ` BALATON Zoltan via
  2020-12-12  0:15 ` [PATCH 6/8] hw/ppc: Delete unused ppc405cr_init() code Peter Maydell
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Switch the sam460ex board to directly creating and configuring the
UIC, rather than doing it via the old ppcuic_init() helper function.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 16 deletions(-)

diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 14e6583eb0d..9cf7aad3833 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -39,6 +39,7 @@
 #include "hw/usb/hcd-ehci.h"
 #include "hw/ppc/fdt.h"
 #include "hw/qdev-properties.h"
+#include "hw/intc/ppc-uic.h"
 
 #include <libfdt.h>
 
@@ -281,7 +282,6 @@ static void sam460ex_init(MachineState *machine)
     hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
     hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
-    qemu_irq *irqs, *uic[4];
     PCIBus *pci_bus;
     PowerPCCPU *cpu;
     CPUPPCState *env;
@@ -293,6 +293,9 @@ static void sam460ex_init(MachineState *machine)
     struct boot_info *boot_info;
     uint8_t *spd_data;
     int success;
+    qemu_irq mal_irqs[4];
+    DeviceState *uic[4];
+    int i;
 
     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
     env = &cpu->env;
@@ -312,13 +315,35 @@ static void sam460ex_init(MachineState *machine)
     ppc4xx_plb_init(env);
 
     /* interrupt controllers */
-    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
-    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
-    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
-    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
+    for (i = 0; i < ARRAY_SIZE(uic); i++) {
+        SysBusDevice *sbd;
+        /*
+         * Number of the first of the two consecutive IRQ inputs on UIC 0
+         * to connect the INT and CINT outputs of UIC n to. The entry
+         * for UIC 0 is ignored, because it connects to the CPU.
+         */
+        const int input_ints[] = { -1, 30, 10, 16 };
+
+        uic[i] = qdev_new(TYPE_PPC_UIC);
+        sbd = SYS_BUS_DEVICE(uic[i]);
+
+        qdev_prop_set_uint32(uic[i], "dcr-base", 0xc0 + i * 0x10);
+        object_property_set_link(OBJECT(uic[i]), "cpu", OBJECT(cpu),
+                                 &error_fatal);
+        sysbus_realize_and_unref(sbd, &error_fatal);
+
+        if (i == 0) {
+            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
+                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
+            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
+                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
+        } else {
+            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
+                               qdev_get_gpio_in(uic[0], input_ints[i]));
+            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
+                               qdev_get_gpio_in(uic[0], input_ints[i] + 1));
+        }
+    }
 
     /* SDRAM controller */
     /* put all RAM on first bank because board has one slot
@@ -331,7 +356,8 @@ static void sam460ex_init(MachineState *machine)
                       ram_bases, ram_sizes, 1);
 
     /* IIC controllers and devices */
-    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
+    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700,
+                               qdev_get_gpio_in(uic[0], 2));
     i2c = PPC4xx_I2C(dev)->bus;
     /* SPD EEPROM on RAM module */
     spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2,
@@ -341,7 +367,8 @@ static void sam460ex_init(MachineState *machine)
     /* RTC */
     i2c_slave_create_simple(i2c, "m41t80", 0x68);
 
-    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
+    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800,
+                               qdev_get_gpio_in(uic[0], 3));
 
     /* External bus controller */
     ppc405_ebc_init(env);
@@ -356,7 +383,14 @@ static void sam460ex_init(MachineState *machine)
     ppc4xx_sdr_init(env);
 
     /* MAL */
-    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
+    /*
+     * TODO if the MAL were a proper QOM device we would not need to
+     * copy its qemu_irqs into an array for ppc4xx_mal_init()'s benefit.
+     */
+    for (i = 0; i < ARRAY_SIZE(mal_irqs); i++) {
+        mal_irqs[0] = qdev_get_gpio_in(uic[2], 3 + i);
+    }
+    ppc4xx_mal_init(env, 4, 16, mal_irqs);
 
     /* DMA */
     ppc4xx_dma_init(env, 0x200);
@@ -369,21 +403,23 @@ static void sam460ex_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
 
     /* USB */
-    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
+    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400,
+                         qdev_get_gpio_in(uic[2], 29));
     dev = qdev_new("sysbus-ohci");
     qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
     qdev_prop_set_uint32(dev, "num-ports", 6);
     sbdev = SYS_BUS_DEVICE(dev);
     sysbus_realize_and_unref(sbdev, &error_fatal);
     sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
-    sysbus_connect_irq(sbdev, 0, uic[2][30]);
+    sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(uic[2], 30));
     usb_create_simple(usb_bus_find(-1), "usb-kbd");
     usb_create_simple(usb_bus_find(-1), "usb-mouse");
 
     /* PCI bus */
     ppc460ex_pcie_init(env);
     /* All PCI irqs are connected to the same UIC pin (cf. UBoot source) */
-    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000, uic[1][0]);
+    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000,
+                               qdev_get_gpio_in(uic[1], 0));
     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
     if (!pci_bus) {
         error_report("couldn't create PCI controller!");
@@ -405,12 +441,14 @@ static void sam460ex_init(MachineState *machine)
     /* SoC has 4 UARTs
      * but board has only one wired and two are present in fdt */
     if (serial_hd(0) != NULL) {
-        serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
+        serial_mm_init(address_space_mem, 0x4ef600300, 0,
+                       qdev_get_gpio_in(uic[1], 1),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hd(1) != NULL) {
-        serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
+        serial_mm_init(address_space_mem, 0x4ef600400, 0,
+                       qdev_get_gpio_in(uic[0], 1),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
                        DEVICE_BIG_ENDIAN);
     }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 6/8] hw/ppc: Delete unused ppc405cr_init() code
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (4 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 5/8] hw/ppc/sam460ex: " Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-12  0:15 ` [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init() Peter Maydell
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

The function ppc405cr_init() has apparently been unused since it was
added in commit 8ecc7913525ecb in 2007.

Remove this dead code, so we don't have to convert it away from using
ppcuic_init().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/ppc405.h    |   6 -
 hw/ppc/ppc405_uc.c | 345 ---------------------------------------------
 2 files changed, 351 deletions(-)

diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h
index 7ed25cfa1bf..e6c702f7e0d 100644
--- a/hw/ppc/ppc405.h
+++ b/hw/ppc/ppc405.h
@@ -62,12 +62,6 @@ ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
 void ppc4xx_plb_init(CPUPPCState *env);
 void ppc405_ebc_init(CPUPPCState *env);
 
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[4],
-                        hwaddr ram_bases[4],
-                        hwaddr ram_sizes[4],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init);
 CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
                         MemoryRegion ram_memories[2],
                         hwaddr ram_bases[2],
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 381720aced9..3e191ae4af5 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -1155,351 +1155,6 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
     qemu_register_reset(ppc4xx_gpt_reset, gpt);
 }
 
-/*****************************************************************************/
-/* PowerPC 405CR */
-enum {
-    PPC405CR_CPC0_PLLMR  = 0x0B0,
-    PPC405CR_CPC0_CR0    = 0x0B1,
-    PPC405CR_CPC0_CR1    = 0x0B2,
-    PPC405CR_CPC0_PSR    = 0x0B4,
-    PPC405CR_CPC0_JTAGID = 0x0B5,
-    PPC405CR_CPC0_ER     = 0x0B9,
-    PPC405CR_CPC0_FR     = 0x0BA,
-    PPC405CR_CPC0_SR     = 0x0BB,
-};
-
-enum {
-    PPC405CR_CPU_CLK   = 0,
-    PPC405CR_TMR_CLK   = 1,
-    PPC405CR_PLB_CLK   = 2,
-    PPC405CR_SDRAM_CLK = 3,
-    PPC405CR_OPB_CLK   = 4,
-    PPC405CR_EXT_CLK   = 5,
-    PPC405CR_UART_CLK  = 6,
-    PPC405CR_CLK_NB    = 7,
-};
-
-typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
-struct ppc405cr_cpc_t {
-    clk_setup_t clk_setup[PPC405CR_CLK_NB];
-    uint32_t sysclk;
-    uint32_t psr;
-    uint32_t cr0;
-    uint32_t cr1;
-    uint32_t jtagid;
-    uint32_t pllmr;
-    uint32_t er;
-    uint32_t fr;
-};
-
-static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
-{
-    uint64_t VCO_out, PLL_out;
-    uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
-    int M, D0, D1, D2;
-
-    D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
-    if (cpc->pllmr & 0x80000000) {
-        D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
-        D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
-        M = D0 * D1 * D2;
-        VCO_out = (uint64_t)cpc->sysclk * M;
-        if (VCO_out < 400000000 || VCO_out > 800000000) {
-            /* PLL cannot lock */
-            cpc->pllmr &= ~0x80000000;
-            goto bypass_pll;
-        }
-        PLL_out = VCO_out / D2;
-    } else {
-        /* Bypass PLL */
-    bypass_pll:
-        M = D0;
-        PLL_out = (uint64_t)cpc->sysclk * M;
-    }
-    CPU_clk = PLL_out;
-    if (cpc->cr1 & 0x00800000)
-        TMR_clk = cpc->sysclk; /* Should have a separate clock */
-    else
-        TMR_clk = CPU_clk;
-    PLB_clk = CPU_clk / D0;
-    SDRAM_clk = PLB_clk;
-    D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
-    OPB_clk = PLB_clk / D0;
-    D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
-    EXT_clk = PLB_clk / D0;
-    D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
-    UART_clk = CPU_clk / D0;
-    /* Setup CPU clocks */
-    clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
-    /* Setup time-base clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
-    /* Setup PLB clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
-    /* Setup SDRAM clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
-    /* Setup OPB clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
-    /* Setup external clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
-    /* Setup UART clock */
-    clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
-}
-
-static uint32_t dcr_read_crcpc (void *opaque, int dcrn)
-{
-    ppc405cr_cpc_t *cpc;
-    uint32_t ret;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405CR_CPC0_PLLMR:
-        ret = cpc->pllmr;
-        break;
-    case PPC405CR_CPC0_CR0:
-        ret = cpc->cr0;
-        break;
-    case PPC405CR_CPC0_CR1:
-        ret = cpc->cr1;
-        break;
-    case PPC405CR_CPC0_PSR:
-        ret = cpc->psr;
-        break;
-    case PPC405CR_CPC0_JTAGID:
-        ret = cpc->jtagid;
-        break;
-    case PPC405CR_CPC0_ER:
-        ret = cpc->er;
-        break;
-    case PPC405CR_CPC0_FR:
-        ret = cpc->fr;
-        break;
-    case PPC405CR_CPC0_SR:
-        ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
-        break;
-    default:
-        /* Avoid gcc warning */
-        ret = 0;
-        break;
-    }
-
-    return ret;
-}
-
-static void dcr_write_crcpc (void *opaque, int dcrn, uint32_t val)
-{
-    ppc405cr_cpc_t *cpc;
-
-    cpc = opaque;
-    switch (dcrn) {
-    case PPC405CR_CPC0_PLLMR:
-        cpc->pllmr = val & 0xFFF77C3F;
-        break;
-    case PPC405CR_CPC0_CR0:
-        cpc->cr0 = val & 0x0FFFFFFE;
-        break;
-    case PPC405CR_CPC0_CR1:
-        cpc->cr1 = val & 0x00800000;
-        break;
-    case PPC405CR_CPC0_PSR:
-        /* Read-only */
-        break;
-    case PPC405CR_CPC0_JTAGID:
-        /* Read-only */
-        break;
-    case PPC405CR_CPC0_ER:
-        cpc->er = val & 0xBFFC0000;
-        break;
-    case PPC405CR_CPC0_FR:
-        cpc->fr = val & 0xBFFC0000;
-        break;
-    case PPC405CR_CPC0_SR:
-        /* Read-only */
-        break;
-    }
-}
-
-static void ppc405cr_cpc_reset (void *opaque)
-{
-    ppc405cr_cpc_t *cpc;
-    int D;
-
-    cpc = opaque;
-    /* Compute PLLMR value from PSR settings */
-    cpc->pllmr = 0x80000000;
-    /* PFWD */
-    switch ((cpc->psr >> 30) & 3) {
-    case 0:
-        /* Bypass */
-        cpc->pllmr &= ~0x80000000;
-        break;
-    case 1:
-        /* Divide by 3 */
-        cpc->pllmr |= 5 << 16;
-        break;
-    case 2:
-        /* Divide by 4 */
-        cpc->pllmr |= 4 << 16;
-        break;
-    case 3:
-        /* Divide by 6 */
-        cpc->pllmr |= 2 << 16;
-        break;
-    }
-    /* PFBD */
-    D = (cpc->psr >> 28) & 3;
-    cpc->pllmr |= (D + 1) << 20;
-    /* PT   */
-    D = (cpc->psr >> 25) & 7;
-    switch (D) {
-    case 0x2:
-        cpc->pllmr |= 0x13;
-        break;
-    case 0x4:
-        cpc->pllmr |= 0x15;
-        break;
-    case 0x5:
-        cpc->pllmr |= 0x16;
-        break;
-    default:
-        break;
-    }
-    /* PDC  */
-    D = (cpc->psr >> 23) & 3;
-    cpc->pllmr |= D << 26;
-    /* ODP  */
-    D = (cpc->psr >> 21) & 3;
-    cpc->pllmr |= D << 10;
-    /* EBPD */
-    D = (cpc->psr >> 17) & 3;
-    cpc->pllmr |= D << 24;
-    cpc->cr0 = 0x0000003C;
-    cpc->cr1 = 0x2B0D8800;
-    cpc->er = 0x00000000;
-    cpc->fr = 0x00000000;
-    ppc405cr_clk_setup(cpc);
-}
-
-static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
-{
-    int D;
-
-    /* XXX: this should be read from IO pins */
-    cpc->psr = 0x00000000; /* 8 bits ROM */
-    /* PFWD */
-    D = 0x2; /* Divide by 4 */
-    cpc->psr |= D << 30;
-    /* PFBD */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 28;
-    /* PDC */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 23;
-    /* PT */
-    D = 0x5; /* M = 16 */
-    cpc->psr |= D << 25;
-    /* ODP */
-    D = 0x1; /* Divide by 2 */
-    cpc->psr |= D << 21;
-    /* EBDP */
-    D = 0x2; /* Divide by 4 */
-    cpc->psr |= D << 17;
-}
-
-static void ppc405cr_cpc_init (CPUPPCState *env, clk_setup_t clk_setup[7],
-                               uint32_t sysclk)
-{
-    ppc405cr_cpc_t *cpc;
-
-    cpc = g_malloc0(sizeof(ppc405cr_cpc_t));
-    memcpy(cpc->clk_setup, clk_setup,
-           PPC405CR_CLK_NB * sizeof(clk_setup_t));
-    cpc->sysclk = sysclk;
-    cpc->jtagid = 0x42051049;
-    ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
-                     &dcr_read_crcpc, &dcr_write_crcpc);
-    ppc405cr_clk_init(cpc);
-    qemu_register_reset(ppc405cr_cpc_reset, cpc);
-}
-
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[4],
-                        hwaddr ram_bases[4],
-                        hwaddr ram_sizes[4],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init)
-{
-    clk_setup_t clk_setup[PPC405CR_CLK_NB];
-    qemu_irq dma_irqs[4];
-    PowerPCCPU *cpu;
-    CPUPPCState *env;
-    qemu_irq *pic, *irqs;
-
-    memset(clk_setup, 0, sizeof(clk_setup));
-    cpu = ppc4xx_init(POWERPC_CPU_TYPE_NAME("405crc"),
-                      &clk_setup[PPC405CR_CPU_CLK],
-                      &clk_setup[PPC405CR_TMR_CLK], sysclk);
-    env = &cpu->env;
-    /* Memory mapped devices registers */
-    /* PLB arbitrer */
-    ppc4xx_plb_init(env);
-    /* PLB to OPB bridge */
-    ppc4xx_pob_init(env);
-    /* OBP arbitrer */
-    ppc4xx_opba_init(0xef600600);
-    /* Universal interrupt controller */
-    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-    *picp = pic;
-    /* SDRAM controller */
-    ppc4xx_sdram_init(env, pic[14], 1, ram_memories,
-                      ram_bases, ram_sizes, do_init);
-    /* External bus controller */
-    ppc405_ebc_init(env);
-    /* DMA controller */
-    dma_irqs[0] = pic[26];
-    dma_irqs[1] = pic[25];
-    dma_irqs[2] = pic[24];
-    dma_irqs[3] = pic[23];
-    ppc405_dma_init(env, dma_irqs);
-    /* Serial ports */
-    if (serial_hd(0) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
-                       DEVICE_BIG_ENDIAN);
-    }
-    if (serial_hd(1) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
-                       PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
-                       DEVICE_BIG_ENDIAN);
-    }
-    /* IIC controller */
-    sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]);
-    /* GPIO */
-    ppc405_gpio_init(0xef600700);
-    /* CPU control */
-    ppc405cr_cpc_init(env, clk_setup, sysclk);
-
-    return env;
-}
-
 /*****************************************************************************/
 /* PowerPC 405EP */
 /* CPU control */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init()
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (5 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 6/8] hw/ppc: Delete unused ppc405cr_init() code Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2021-01-11 19:09   ` BALATON Zoltan
  2020-12-12  0:15 ` [PATCH 8/8] hw/ppc: Remove unused ppcuic_init() Peter Maydell
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Switch the ppc405_uc boards to directly creating and configuring the
UIC, rather than doing it via the old ppcuic_init() helper function.

We retain the API feature of ppc405ep_init() where it passes back
something allowing the callers to wire up devices to the UIC if
they need to, even though neither of the callsites currently makes
use of this ability -- instead of passing back the qemu_irq array
we pass back the UIC DeviceState.

This fixes a trivial Coverity-detected memory leak where
we were leaking the array of IRQs returned by ppcuic_init().

Fixes: Coverity CID 1421922
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/ppc/ppc405.h        |  2 +-
 hw/ppc/ppc405_boards.c |  8 ++---
 hw/ppc/ppc405_uc.c     | 70 +++++++++++++++++++++++++-----------------
 3 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h
index e6c702f7e0d..c58f739886a 100644
--- a/hw/ppc/ppc405.h
+++ b/hw/ppc/ppc405.h
@@ -66,7 +66,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
                         MemoryRegion ram_memories[2],
                         hwaddr ram_bases[2],
                         hwaddr ram_sizes[2],
-                        uint32_t sysclk, qemu_irq **picp,
+                        uint32_t sysclk, DeviceState **uicdev,
                         int do_init);
 
 #endif /* PPC405_H */
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index b7249f21cf2..8f77887fb18 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -151,7 +151,6 @@ static void ref405ep_init(MachineState *machine)
     CPUPPCState *env;
     DeviceState *dev;
     SysBusDevice *s;
-    qemu_irq *pic;
     MemoryRegion *bios;
     MemoryRegion *sram = g_new(MemoryRegion, 1);
     ram_addr_t bdloc;
@@ -167,6 +166,7 @@ static void ref405ep_init(MachineState *machine)
     int len;
     DriveInfo *dinfo;
     MemoryRegion *sysmem = get_system_memory();
+    DeviceState *uicdev;
 
     if (machine->ram_size != mc->default_ram_size) {
         char *sz = size_to_str(mc->default_ram_size);
@@ -184,7 +184,7 @@ static void ref405ep_init(MachineState *machine)
     ram_bases[1] = 0x00000000;
     ram_sizes[1] = 0x00000000;
     env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
-                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
+                        33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
     /* allocate SRAM */
     sram_size = 512 * KiB;
     memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size,
@@ -429,7 +429,6 @@ static void taihu_405ep_init(MachineState *machine)
     const char *kernel_filename = machine->kernel_filename;
     const char *initrd_filename = machine->initrd_filename;
     char *filename;
-    qemu_irq *pic;
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *bios;
     MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
@@ -440,6 +439,7 @@ static void taihu_405ep_init(MachineState *machine)
     int linux_boot;
     int fl_idx;
     DriveInfo *dinfo;
+    DeviceState *uicdev;
 
     if (machine->ram_size != mc->default_ram_size) {
         char *sz = size_to_str(mc->default_ram_size);
@@ -459,7 +459,7 @@ static void taihu_405ep_init(MachineState *machine)
                              "taihu_405ep.ram-1", machine->ram, ram_bases[1],
                              ram_sizes[1]);
     ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
-                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
+                  33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
     /* allocate and load BIOS */
     fl_idx = 0;
 #if defined(USE_FLASH_BIOS)
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 3e191ae4af5..fe047074a17 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -36,6 +36,9 @@
 #include "sysemu/sysemu.h"
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
+#include "hw/intc/ppc-uic.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
 
 //#define DEBUG_OPBA
 //#define DEBUG_SDRAM
@@ -1446,14 +1449,15 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
                         MemoryRegion ram_memories[2],
                         hwaddr ram_bases[2],
                         hwaddr ram_sizes[2],
-                        uint32_t sysclk, qemu_irq **picp,
+                        uint32_t sysclk, DeviceState **uicdevp,
                         int do_init)
 {
     clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
     qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
     PowerPCCPU *cpu;
     CPUPPCState *env;
-    qemu_irq *pic, *irqs;
+    DeviceState *uicdev;
+    SysBusDevice *uicsbd;
 
     memset(clk_setup, 0, sizeof(clk_setup));
     /* init CPUs */
@@ -1474,59 +1478,69 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
     /* Initialize timers */
     ppc_booke_timers_init(cpu, sysclk, 0);
     /* Universal interrupt controller */
-    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
-    irqs[PPCUIC_OUTPUT_INT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
-    irqs[PPCUIC_OUTPUT_CINT] =
-        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
-    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-    *picp = pic;
+    uicdev = qdev_new(TYPE_PPC_UIC);
+    uicsbd = SYS_BUS_DEVICE(uicdev);
+
+    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
+                             &error_fatal);
+    sysbus_realize_and_unref(uicsbd, &error_fatal);
+
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
+    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
+                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
+
+    *uicdevp = uicdev;
+
     /* SDRAM controller */
         /* XXX 405EP has no ECC interrupt */
-    ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
+    ppc4xx_sdram_init(env, qdev_get_gpio_in(uicdev, 17), 2, ram_memories,
                       ram_bases, ram_sizes, do_init);
     /* External bus controller */
     ppc405_ebc_init(env);
     /* DMA controller */
-    dma_irqs[0] = pic[5];
-    dma_irqs[1] = pic[6];
-    dma_irqs[2] = pic[7];
-    dma_irqs[3] = pic[8];
+    dma_irqs[0] = qdev_get_gpio_in(uicdev, 5);
+    dma_irqs[1] = qdev_get_gpio_in(uicdev, 6);
+    dma_irqs[2] = qdev_get_gpio_in(uicdev, 7);
+    dma_irqs[3] = qdev_get_gpio_in(uicdev, 8);
     ppc405_dma_init(env, dma_irqs);
     /* IIC controller */
-    sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]);
+    sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500,
+                         qdev_get_gpio_in(uicdev, 2));
     /* GPIO */
     ppc405_gpio_init(0xef600700);
     /* Serial ports */
     if (serial_hd(0) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+        serial_mm_init(address_space_mem, 0xef600300, 0,
+                       qdev_get_gpio_in(uicdev, 0),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
                        DEVICE_BIG_ENDIAN);
     }
     if (serial_hd(1) != NULL) {
-        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+        serial_mm_init(address_space_mem, 0xef600400, 0,
+                       qdev_get_gpio_in(uicdev, 1),
                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
                        DEVICE_BIG_ENDIAN);
     }
     /* OCM */
     ppc405_ocm_init(env);
     /* GPT */
-    gpt_irqs[0] = pic[19];
-    gpt_irqs[1] = pic[20];
-    gpt_irqs[2] = pic[21];
-    gpt_irqs[3] = pic[22];
-    gpt_irqs[4] = pic[23];
+    gpt_irqs[0] = qdev_get_gpio_in(uicdev, 19);
+    gpt_irqs[1] = qdev_get_gpio_in(uicdev, 20);
+    gpt_irqs[2] = qdev_get_gpio_in(uicdev, 21);
+    gpt_irqs[3] = qdev_get_gpio_in(uicdev, 22);
+    gpt_irqs[4] = qdev_get_gpio_in(uicdev, 23);
     ppc4xx_gpt_init(0xef600000, gpt_irqs);
     /* PCI */
-    /* Uses pic[3], pic[16], pic[18] */
+    /* Uses UIC IRQs 3, 16, 18 */
     /* MAL */
-    mal_irqs[0] = pic[11];
-    mal_irqs[1] = pic[12];
-    mal_irqs[2] = pic[13];
-    mal_irqs[3] = pic[14];
+    mal_irqs[0] = qdev_get_gpio_in(uicdev, 11);
+    mal_irqs[1] = qdev_get_gpio_in(uicdev, 12);
+    mal_irqs[2] = qdev_get_gpio_in(uicdev, 13);
+    mal_irqs[3] = qdev_get_gpio_in(uicdev, 14);
     ppc4xx_mal_init(env, 4, 2, mal_irqs);
     /* Ethernet */
-    /* Uses pic[9], pic[15], pic[17] */
+    /* Uses UIC IRQs 9, 15, 17 */
     /* CPU control */
     ppc405ep_cpc_init(env, clk_setup, sysclk);
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH 8/8] hw/ppc: Remove unused ppcuic_init()
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (6 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init() Peter Maydell
@ 2020-12-12  0:15 ` Peter Maydell
  2020-12-13 14:35   ` Edgar E. Iglesias
  2020-12-12 17:43 ` [PATCH 0/8] hw/ppc: Convert UIC device to QOM BALATON Zoltan via
  2020-12-14  6:00 ` David Gibson
  9 siblings, 1 reply; 39+ messages in thread
From: Peter Maydell @ 2020-12-12  0:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

Now we've converted all the callsites to directly create the QOM UIC
device themselves, the ppcuic_init() function is unused and can be
removed. The enum defining PPCUIC symbolic constants can be moved
to the ppc-uic.h header where it more naturally belongs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/intc/ppc-uic.h |  7 +++++++
 include/hw/ppc/ppc4xx.h   |  9 ---------
 hw/ppc/ppc4xx_devs.c      | 38 --------------------------------------
 3 files changed, 7 insertions(+), 47 deletions(-)

diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
index e614e2ffd80..22dd5e5ac2c 100644
--- a/include/hw/intc/ppc-uic.h
+++ b/include/hw/intc/ppc-uic.h
@@ -47,6 +47,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
 
 #define UIC_MAX_IRQ 32
 
+/* Symbolic constants for the sysbus IRQ outputs */
+enum {
+    PPCUIC_OUTPUT_INT = 0,
+    PPCUIC_OUTPUT_CINT = 1,
+    PPCUIC_OUTPUT_NB,
+};
+
 struct PPCUIC {
     /*< private >*/
     SysBusDevice parent_obj;
diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
index cc19c8da5be..980f964b5a9 100644
--- a/include/hw/ppc/ppc4xx.h
+++ b/include/hw/ppc/ppc4xx.h
@@ -33,15 +33,6 @@ PowerPCCPU *ppc4xx_init(const char *cpu_model,
                         clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
                         uint32_t sysclk);
 
-/* PowerPC 4xx universal interrupt controller */
-enum {
-    PPCUIC_OUTPUT_INT = 0,
-    PPCUIC_OUTPUT_CINT = 1,
-    PPCUIC_OUTPUT_NB,
-};
-qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
-                       uint32_t dcr_base, int has_ssr, int has_vr);
-
 void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
                         MemoryRegion ram_memories[],
                         hwaddr ram_bases[], hwaddr ram_sizes[],
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index ffe4cf43e88..fe9d4f7155e 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -77,44 +77,6 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
     return cpu;
 }
 
-/*****************************************************************************/
-/* "Universal" Interrupt controller */
-
-qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
-                       uint32_t dcr_base, int has_ssr, int has_vr)
-{
-    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
-    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
-    qemu_irq *uic_irqs;
-    int i;
-
-    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
-    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
-    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
-                             &error_fatal);
-    sysbus_realize_and_unref(uicsbd, &error_fatal);
-
-    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
-    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
-
-    /*
-     * Return an allocated array of the UIC's input IRQ lines.
-     * This is an ugly temporary API to retain compatibility with
-     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
-     * None of the callers free this array, so it is leaked -- but
-     * so was the array allocated by qemu_allocate_irqs() in the
-     * old code.
-     *
-     * The callers should just instantiate the UIC and wire it up
-     * themselves rather than passing qemu_irq* in and out of this function.
-     */
-    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
-    for (i = 0; i < UIC_MAX_IRQ; i++) {
-        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
-    }
-    return uic_irqs;
-}
-
 /*****************************************************************************/
 /* SDRAM controller */
 typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
@ 2020-12-12 16:57   ` BALATON Zoltan via
  2020-12-12 18:27   ` BALATON Zoltan via
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 16:57 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

[-- Attachment #1: Type: text/plain, Size: 25180 bytes --]

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> in hw/intc.
>
> The ppcuic_init() function is retained for the moment with its current
> interface; in subsequent commits this will be tidied up to avoid the
> allocation of an irq array.
>
> This conversion adds VMState support.
>
> It leaves the LOG_UIC() macro as-is to maximise the extent to which
> this is simply code-movement rather than a rewrite (in new code it
> would be better to use tracepoints).
>
> The default property values for dcr-base and use-vectors are set to
> match those use by most of our boards with a UIC.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> include/hw/intc/ppc-uic.h |  73 +++++++++
> hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
> hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
> MAINTAINERS               |   2 +
> hw/intc/Kconfig           |   3 +
> hw/intc/meson.build       |   1 +
> hw/ppc/Kconfig            |   1 +
> 7 files changed, 431 insertions(+), 237 deletions(-)
> create mode 100644 include/hw/intc/ppc-uic.h
> create mode 100644 hw/intc/ppc-uic.c

Underscore seems to be more common in file names so maybe ppc_uid.[ch], 
that also better matches function and config option names.

Regards,
BALATON Zoltan

> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> new file mode 100644
> index 00000000000..e614e2ffd80
> --- /dev/null
> +++ b/include/hw/intc/ppc-uic.h
> @@ -0,0 +1,73 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_INTC_PPC_UIC_H
> +#define HW_INTC_PPC_UIC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_PPC_UIC "ppc-uic"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
> +
> +/*
> + * QEMU interface:
> + * QOM property "cpu": link to the PPC CPU
> + *    (no default, must be set)
> + * QOM property "dcr-base": base of the bank of DCR registers for the UIC
> + *    (default 0x30)
> + * QOM property "use-vectors": true if the UIC has vector registers
> + *    (default true)
> + * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
> + * sysbus IRQs:
> + *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
> + *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
> + */
> +
> +#define UIC_MAX_IRQ 32
> +
> +struct PPCUIC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +    qemu_irq output_cint;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    uint32_t dcr_base;
> +    bool use_vectors;
> +
> +    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> +    uint32_t uicsr;  /* Status register */
> +    uint32_t uicer;  /* Enable register */
> +    uint32_t uiccr;  /* Critical register */
> +    uint32_t uicpr;  /* Polarity register */
> +    uint32_t uictr;  /* Triggering register */
> +    uint32_t uicvcr; /* Vector configuration register */
> +    uint32_t uicvr;
> +};
> +
> +#endif
> diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
> new file mode 100644
> index 00000000000..b21951eea83
> --- /dev/null
> +++ b/hw/intc/ppc-uic.c
> @@ -0,0 +1,321 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "include/hw/intc/ppc-uic.h"
> +#include "hw/irq.h"
> +#include "cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +
> +enum {
> +    DCR_UICSR  = 0x000,
> +    DCR_UICSRS = 0x001,
> +    DCR_UICER  = 0x002,
> +    DCR_UICCR  = 0x003,
> +    DCR_UICPR  = 0x004,
> +    DCR_UICTR  = 0x005,
> +    DCR_UICMSR = 0x006,
> +    DCR_UICVR  = 0x007,
> +    DCR_UICVCR = 0x008,
> +    DCR_UICMAX = 0x009,
> +};
> +
> +/*#define DEBUG_UIC*/
> +
> +#ifdef DEBUG_UIC
> +#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
> +#else
> +#  define LOG_UIC(...) do { } while (0)
> +#endif
> +
> +static void ppcuic_trigger_irq(PPCUIC *uic)
> +{
> +    uint32_t ir, cr;
> +    int start, end, inc, i;
> +
> +    /* Trigger interrupt if any is pending */
> +    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> +    cr = uic->uicsr & uic->uicer & uic->uiccr;
> +    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> +                " uiccr %08" PRIx32 "\n"
> +                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> +                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> +                uic->uicsr & uic->uicer, ir, cr);
> +    if (ir != 0x0000000) {
> +        LOG_UIC("Raise UIC interrupt\n");
> +        qemu_irq_raise(uic->output_int);
> +    } else {
> +        LOG_UIC("Lower UIC interrupt\n");
> +        qemu_irq_lower(uic->output_int);
> +    }
> +    /* Trigger critical interrupt if any is pending and update vector */
> +    if (cr != 0x0000000) {
> +        qemu_irq_raise(uic->output_cint);
> +        if (uic->use_vectors) {
> +            /* Compute critical IRQ vector */
> +            if (uic->uicvcr & 1) {
> +                start = 31;
> +                end = 0;
> +                inc = -1;
> +            } else {
> +                start = 0;
> +                end = 31;
> +                inc = 1;
> +            }
> +            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> +            for (i = start; i <= end; i += inc) {
> +                if (cr & (1 << i)) {
> +                    uic->uicvr += (i - start) * 512 * inc;
> +                    break;
> +                }
> +            }
> +        }
> +        LOG_UIC("Raise UIC critical interrupt - "
> +                    "vector %08" PRIx32 "\n", uic->uicvr);
> +    } else {
> +        LOG_UIC("Lower UIC critical interrupt\n");
> +        qemu_irq_lower(uic->output_cint);
> +        uic->uicvr = 0x00000000;
> +    }
> +}
> +
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    PPCUIC *uic;
> +    uint32_t mask, sr;
> +
> +    uic = opaque;
> +    mask = 1U << (31 - irq_num);
> +    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> +                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> +                __func__, irq_num, level,
> +                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> +    if (irq_num < 0 || irq_num > 31) {
> +        return;
> +    }
> +    sr = uic->uicsr;
> +
> +    /* Update status register */
> +    if (uic->uictr & mask) {
> +        /* Edge sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +        }
> +    } else {
> +        /* Level sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +            uic->level |= mask;
> +        } else {
> +            uic->uicsr &= ~mask;
> +            uic->level &= ~mask;
> +        }
> +    }
> +    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> +                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> +    if (sr != uic->uicsr) {
> +        ppcuic_trigger_irq(uic);
> +    }
> +}
> +
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
> +{
> +    PPCUIC *uic;
> +    uint32_t ret;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +    case DCR_UICSRS:
> +        ret = uic->uicsr;
> +        break;
> +    case DCR_UICER:
> +        ret = uic->uicer;
> +        break;
> +    case DCR_UICCR:
> +        ret = uic->uiccr;
> +        break;
> +    case DCR_UICPR:
> +        ret = uic->uicpr;
> +        break;
> +    case DCR_UICTR:
> +        ret = uic->uictr;
> +        break;
> +    case DCR_UICMSR:
> +        ret = uic->uicsr & uic->uicer;
> +        break;
> +    case DCR_UICVR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvr;
> +        break;
> +    case DCR_UICVCR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvcr;
> +        break;
> +    default:
> +    no_read:
> +        ret = 0x00000000;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPCUIC *uic;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +        uic->uicsr &= ~val;
> +        uic->uicsr |= uic->level;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICSRS:
> +        uic->uicsr |= val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICER:
> +        uic->uicer = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICCR:
> +        uic->uiccr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICPR:
> +        uic->uicpr = val;
> +        break;
> +    case DCR_UICTR:
> +        uic->uictr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICMSR:
> +        break;
> +    case DCR_UICVR:
> +        break;
> +    case DCR_UICVCR:
> +        uic->uicvcr = val & 0xFFFFFFFD;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    }
> +}
> +
> +static void ppc_uic_reset(DeviceState *dev)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +
> +    uic->uiccr = 0x00000000;
> +    uic->uicer = 0x00000000;
> +    uic->uicpr = 0x00000000;
> +    uic->uicsr = 0x00000000;
> +    uic->uictr = 0x00000000;
> +    if (uic->use_vectors) {
> +        uic->uicvcr = 0x00000000;
> +        uic->uicvr = 0x0000000;
> +    }
> +}
> +
> +static void ppc_uic_realize(DeviceState *dev, Error **errp)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    PowerPCCPU *cpu;
> +    int i;
> +
> +    if (!uic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "ppc-uic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    cpu = POWERPC_CPU(uic->cpu);
> +    for (i = 0; i < DCR_UICMAX; i++) {
> +        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
> +                         &dcr_read_uic, &dcr_write_uic);
> +    }
> +
> +    sysbus_init_irq(sbd, &uic->output_int);
> +    sysbus_init_irq(sbd, &uic->output_cint);
> +    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
> +}
> +
> +static Property ppc_uic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
> +    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription ppc_uic_vmstate = {
> +    .name = "ppc-uic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, PPCUIC),
> +        VMSTATE_UINT32(uicsr, PPCUIC),
> +        VMSTATE_UINT32(uicer, PPCUIC),
> +        VMSTATE_UINT32(uiccr, PPCUIC),
> +        VMSTATE_UINT32(uicpr, PPCUIC),
> +        VMSTATE_UINT32(uictr, PPCUIC),
> +        VMSTATE_UINT32(uicvcr, PPCUIC),
> +        VMSTATE_UINT32(uicvr, PPCUIC),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void ppc_uic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ppc_uic_reset;
> +    dc->realize = ppc_uic_realize;
> +    dc->vmsd = &ppc_uic_vmstate;
> +    device_class_set_props(dc, ppc_uic_properties);
> +}
> +
> +static const TypeInfo ppc_uic_info = {
> +    .name = TYPE_PPC_UIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PPCUIC),
> +    .class_init = ppc_uic_class_init,
> +};
> +
> +static void ppc_uic_register_types(void)
> +{
> +    type_register_static(&ppc_uic_info);
> +}
> +
> +type_init(ppc_uic_register_types);
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f2f9ca4ffec..ffe4cf43e88 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -30,9 +30,12 @@
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/ppc4xx.h"
> #include "hw/boards.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> #include "qemu/log.h"
> #include "exec/address-spaces.h"
> #include "qemu/error-report.h"
> +#include "qapi/error.h"
>
> /*#define DEBUG_UIC*/
>
> @@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>
> /*****************************************************************************/
> /* "Universal" Interrupt controller */
> -enum {
> -    DCR_UICSR  = 0x000,
> -    DCR_UICSRS = 0x001,
> -    DCR_UICER  = 0x002,
> -    DCR_UICCR  = 0x003,
> -    DCR_UICPR  = 0x004,
> -    DCR_UICTR  = 0x005,
> -    DCR_UICMSR = 0x006,
> -    DCR_UICVR  = 0x007,
> -    DCR_UICVCR = 0x008,
> -    DCR_UICMAX = 0x009,
> -};
> -
> -#define UIC_MAX_IRQ 32
> -typedef struct ppcuic_t ppcuic_t;
> -struct ppcuic_t {
> -    uint32_t dcr_base;
> -    int use_vectors;
> -    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> -    uint32_t uicsr;  /* Status register */
> -    uint32_t uicer;  /* Enable register */
> -    uint32_t uiccr;  /* Critical register */
> -    uint32_t uicpr;  /* Polarity register */
> -    uint32_t uictr;  /* Triggering register */
> -    uint32_t uicvcr; /* Vector configuration register */
> -    uint32_t uicvr;
> -    qemu_irq *irqs;
> -};
> -
> -static void ppcuic_trigger_irq(ppcuic_t *uic)
> -{
> -    uint32_t ir, cr;
> -    int start, end, inc, i;
> -
> -    /* Trigger interrupt if any is pending */
> -    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> -    cr = uic->uicsr & uic->uicer & uic->uiccr;
> -    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> -                " uiccr %08" PRIx32 "\n"
> -                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> -                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> -                uic->uicsr & uic->uicer, ir, cr);
> -    if (ir != 0x0000000) {
> -        LOG_UIC("Raise UIC interrupt\n");
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    } else {
> -        LOG_UIC("Lower UIC interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    }
> -    /* Trigger critical interrupt if any is pending and update vector */
> -    if (cr != 0x0000000) {
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        if (uic->use_vectors) {
> -            /* Compute critical IRQ vector */
> -            if (uic->uicvcr & 1) {
> -                start = 31;
> -                end = 0;
> -                inc = -1;
> -            } else {
> -                start = 0;
> -                end = 31;
> -                inc = 1;
> -            }
> -            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> -            for (i = start; i <= end; i += inc) {
> -                if (cr & (1 << i)) {
> -                    uic->uicvr += (i - start) * 512 * inc;
> -                    break;
> -                }
> -            }
> -        }
> -        LOG_UIC("Raise UIC critical interrupt - "
> -                    "vector %08" PRIx32 "\n", uic->uicvr);
> -    } else {
> -        LOG_UIC("Lower UIC critical interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        uic->uicvr = 0x00000000;
> -    }
> -}
> -
> -static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> -{
> -    ppcuic_t *uic;
> -    uint32_t mask, sr;
> -
> -    uic = opaque;
> -    mask = 1U << (31 - irq_num);
> -    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> -                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> -                __func__, irq_num, level,
> -                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31) {
> -        return;
> -    }
> -    sr = uic->uicsr;
> -
> -    /* Update status register */
> -    if (uic->uictr & mask) {
> -        /* Edge sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -        }
> -    } else {
> -        /* Level sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -            uic->level |= mask;
> -        } else {
> -            uic->uicsr &= ~mask;
> -            uic->level &= ~mask;
> -        }
> -    }
> -    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> -                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr) {
> -        ppcuic_trigger_irq(uic);
> -    }
> -}
> -
> -static uint32_t dcr_read_uic(void *opaque, int dcrn)
> -{
> -    ppcuic_t *uic;
> -    uint32_t ret;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -    case DCR_UICSRS:
> -        ret = uic->uicsr;
> -        break;
> -    case DCR_UICER:
> -        ret = uic->uicer;
> -        break;
> -    case DCR_UICCR:
> -        ret = uic->uiccr;
> -        break;
> -    case DCR_UICPR:
> -        ret = uic->uicpr;
> -        break;
> -    case DCR_UICTR:
> -        ret = uic->uictr;
> -        break;
> -    case DCR_UICMSR:
> -        ret = uic->uicsr & uic->uicer;
> -        break;
> -    case DCR_UICVR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvr;
> -        break;
> -    case DCR_UICVCR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvcr;
> -        break;
> -    default:
> -    no_read:
> -        ret = 0x00000000;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -        uic->uicsr &= ~val;
> -        uic->uicsr |= uic->level;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICSRS:
> -        uic->uicsr |= val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICER:
> -        uic->uicer = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICCR:
> -        uic->uiccr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICPR:
> -        uic->uicpr = val;
> -        break;
> -    case DCR_UICTR:
> -        uic->uictr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICMSR:
> -        break;
> -    case DCR_UICVR:
> -        break;
> -    case DCR_UICVCR:
> -        uic->uicvcr = val & 0xFFFFFFFD;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    }
> -}
> -
> -static void ppcuic_reset (void *opaque)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    uic->uiccr = 0x00000000;
> -    uic->uicer = 0x00000000;
> -    uic->uicpr = 0x00000000;
> -    uic->uicsr = 0x00000000;
> -    uic->uictr = 0x00000000;
> -    if (uic->use_vectors) {
> -        uic->uicvcr = 0x00000000;
> -        uic->uicvr = 0x0000000;
> -    }
> -}
>
> qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
>                        uint32_t dcr_base, int has_ssr, int has_vr)
> {
> -    ppcuic_t *uic;
> +    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> +    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> +    qemu_irq *uic_irqs;
>     int i;
>
> -    uic = g_malloc0(sizeof(ppcuic_t));
> -    uic->dcr_base = dcr_base;
> -    uic->irqs = irqs;
> -    if (has_vr)
> -        uic->use_vectors = 1;
> -    for (i = 0; i < DCR_UICMAX; i++) {
> -        ppc_dcr_register(env, dcr_base + i, uic,
> -                         &dcr_read_uic, &dcr_write_uic);
> -    }
> -    qemu_register_reset(ppcuic_reset, uic);
> +    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> +    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
>
> -    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> +
> +    /*
> +     * Return an allocated array of the UIC's input IRQ lines.
> +     * This is an ugly temporary API to retain compatibility with
> +     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> +     * None of the callers free this array, so it is leaked -- but
> +     * so was the array allocated by qemu_allocate_irqs() in the
> +     * old code.
> +     *
> +     * The callers should just instantiate the UIC and wire it up
> +     * themselves rather than passing qemu_irq* in and out of this function.
> +     */
> +    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> +    for (i = 0; i < UIC_MAX_IRQ; i++) {
> +        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> +    }
> +    return uic_irqs;
> }
>
> /*****************************************************************************/
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa39490a244..24218800b16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
> F: hw/i2c/ppc4xx_i2c.c
> F: include/hw/ppc/ppc4xx.h
> F: include/hw/i2c/ppc4xx_i2c.h
> +F: hw/intc/ppc-uic.c
> +F: include/hw/intc/ppc-uic.h
>
> Character devices
> M: Marc-André Lureau <marcandre.lureau@redhat.com>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index d07954086a5..468d548ca77 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,6 +62,9 @@ config S390_FLIC_KVM
> config OMPIC
>     bool
>
> +config PPC_UIC
> +    bool
> +
> config RX_ICU
>     bool
>
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 3f82cc230ad..d7dadbe5034 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
> specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
> specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
> specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
> +specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
> specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
> specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index dd86e664d21..982d55f5875 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -53,6 +53,7 @@ config PPC4XX
>     bool
>     select BITBANG_I2C
>     select PCI
> +    select PPC_UIC
>
> config SAM460EX
>     bool
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 5/8] hw/ppc/sam460ex: " Peter Maydell
@ 2020-12-12 17:17   ` BALATON Zoltan via
  2020-12-12 18:11     ` Peter Maydell
  2020-12-12 19:53   ` BALATON Zoltan via
  1 sibling, 1 reply; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 17:17 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Switch the sam460ex board to directly creating and configuring the
> UIC, rather than doing it via the old ppcuic_init() helper function.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 54 insertions(+), 16 deletions(-)

More than 3 times as much than before, qdev seems to be overly verbose and 
less readable but if that's the preferred way then be it.

> diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
> index 14e6583eb0d..9cf7aad3833 100644
> --- a/hw/ppc/sam460ex.c
> +++ b/hw/ppc/sam460ex.c
> @@ -39,6 +39,7 @@
> #include "hw/usb/hcd-ehci.h"
> #include "hw/ppc/fdt.h"
> #include "hw/qdev-properties.h"
> +#include "hw/intc/ppc-uic.h"
>
> #include <libfdt.h>
>
> @@ -281,7 +282,6 @@ static void sam460ex_init(MachineState *machine)
>     hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
>     hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
>     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
> -    qemu_irq *irqs, *uic[4];
>     PCIBus *pci_bus;
>     PowerPCCPU *cpu;
>     CPUPPCState *env;
> @@ -293,6 +293,9 @@ static void sam460ex_init(MachineState *machine)
>     struct boot_info *boot_info;
>     uint8_t *spd_data;
>     int success;
> +    qemu_irq mal_irqs[4];
> +    DeviceState *uic[4];
> +    int i;

Maybe keep this where it was above instead of moving to the end and keep 
DeviceState *uic[4]; first so the two others that would be removed later 
are next to each other (just to make patches simpler and keep the order of 
variables which may be roughly as they appear below).

>     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>     env = &cpu->env;
> @@ -312,13 +315,35 @@ static void sam460ex_init(MachineState *machine)
>     ppc4xx_plb_init(env);
>
>     /* interrupt controllers */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];

Unrelated to this, but I wonder why do we need these casts? Could we just 
define env->irq_inputs as qemu_irq array in the first place? It's now void 
** which according to the comment next to it may be because once it may 
have been used for different implementations but by now maybe it's only 
used for what its name implies? I haven't checked though if it could be 
cleaned up just raising it if anyone's interested to have a look as there 
are such casts at a lot of other places too.

> -    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
> -    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
> -    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
> -    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
> +    for (i = 0; i < ARRAY_SIZE(uic); i++) {
> +        SysBusDevice *sbd;

There's already a SysBusDevice *sbdev; defined for similar cases that you 
could reuse here.

> +        /*
> +         * Number of the first of the two consecutive IRQ inputs on UIC 0
> +         * to connect the INT and CINT outputs of UIC n to. The entry

This comment confused me a bit, while it's precise is it possible to say 
it in a simpler way? I think these are how uic[1-3] are cascaded through 
uic[0] similar to how the PICs in a PC are cascaded.

> +         * for UIC 0 is ignored, because it connects to the CPU.
> +         */
> +        const int input_ints[] = { -1, 30, 10, 16 };
> +
> +        uic[i] = qdev_new(TYPE_PPC_UIC);
> +        sbd = SYS_BUS_DEVICE(uic[i]);
> +
> +        qdev_prop_set_uint32(uic[i], "dcr-base", 0xc0 + i * 0x10);
> +        object_property_set_link(OBJECT(uic[i]), "cpu", OBJECT(cpu),
> +                                 &error_fatal);
> +        sysbus_realize_and_unref(sbd, &error_fatal);
> +
> +        if (i == 0) {
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
> +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +        } else {
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> +                               qdev_get_gpio_in(uic[0], input_ints[i]));
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> +                               qdev_get_gpio_in(uic[0], input_ints[i] + 1));
> +        }
> +    }
>
>     /* SDRAM controller */
>     /* put all RAM on first bank because board has one slot
> @@ -331,7 +356,8 @@ static void sam460ex_init(MachineState *machine)
>                       ram_bases, ram_sizes, 1);
>
>     /* IIC controllers and devices */
> -    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700,
> +                               qdev_get_gpio_in(uic[0], 2));
>     i2c = PPC4xx_I2C(dev)->bus;
>     /* SPD EEPROM on RAM module */
>     spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2,
> @@ -341,7 +367,8 @@ static void sam460ex_init(MachineState *machine)
>     /* RTC */
>     i2c_slave_create_simple(i2c, "m41t80", 0x68);
>
> -    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800,
> +                               qdev_get_gpio_in(uic[0], 3));
>
>     /* External bus controller */
>     ppc405_ebc_init(env);
> @@ -356,7 +383,14 @@ static void sam460ex_init(MachineState *machine)
>     ppc4xx_sdr_init(env);
>
>     /* MAL */
> -    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
> +    /*
> +     * TODO if the MAL were a proper QOM device we would not need to
> +     * copy its qemu_irqs into an array for ppc4xx_mal_init()'s benefit.
> +     */

It's not a todo for sam460ex so maybe put it in the file where mal is if 
you want to note it somewhere? (Other sites using the mal may also need 
updating not just this one when this is cleaned up.)

I'll reply more about testing in the cover letter.

Regards,
BALATON Zoltan

> +    for (i = 0; i < ARRAY_SIZE(mal_irqs); i++) {
> +        mal_irqs[0] = qdev_get_gpio_in(uic[2], 3 + i);
> +    }
> +    ppc4xx_mal_init(env, 4, 16, mal_irqs);
>
>     /* DMA */
>     ppc4xx_dma_init(env, 0x200);
> @@ -369,21 +403,23 @@ static void sam460ex_init(MachineState *machine)
>     memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
>
>     /* USB */
> -    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
> +    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400,
> +                         qdev_get_gpio_in(uic[2], 29));
>     dev = qdev_new("sysbus-ohci");
>     qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
>     qdev_prop_set_uint32(dev, "num-ports", 6);
>     sbdev = SYS_BUS_DEVICE(dev);
>     sysbus_realize_and_unref(sbdev, &error_fatal);
>     sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
> -    sysbus_connect_irq(sbdev, 0, uic[2][30]);
> +    sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(uic[2], 30));
>     usb_create_simple(usb_bus_find(-1), "usb-kbd");
>     usb_create_simple(usb_bus_find(-1), "usb-mouse");
>
>     /* PCI bus */
>     ppc460ex_pcie_init(env);
>     /* All PCI irqs are connected to the same UIC pin (cf. UBoot source) */
> -    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000, uic[1][0]);
> +    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000,
> +                               qdev_get_gpio_in(uic[1], 0));
>     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>     if (!pci_bus) {
>         error_report("couldn't create PCI controller!");
> @@ -405,12 +441,14 @@ static void sam460ex_init(MachineState *machine)
>     /* SoC has 4 UARTs
>      * but board has only one wired and two are present in fdt */
>     if (serial_hd(0) != NULL) {
> -        serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
> +        serial_mm_init(address_space_mem, 0x4ef600300, 0,
> +                       qdev_get_gpio_in(uic[1], 1),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
>                        DEVICE_BIG_ENDIAN);
>     }
>     if (serial_hd(1) != NULL) {
> -        serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
> +        serial_mm_init(address_space_mem, 0x4ef600400, 0,
> +                       qdev_get_gpio_in(uic[0], 1),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
>                        DEVICE_BIG_ENDIAN);
>     }
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/8] hw/ppc: Convert UIC device to QOM
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (7 preceding siblings ...)
  2020-12-12  0:15 ` [PATCH 8/8] hw/ppc: Remove unused ppcuic_init() Peter Maydell
@ 2020-12-12 17:43 ` BALATON Zoltan via
  2020-12-12 18:13   ` Peter Maydell
  2020-12-14  6:00 ` David Gibson
  9 siblings, 1 reply; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 17:43 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> This patchseries converts the PPC UIC "Universal Interrupt
> Controller" to a QOM device.  My main reason for doing it is that

Thanks for doing this clean up.

> this fixes a couple of long-standing trivial Coverity issues -- the
> current ppcuic_init() function allocates an array of qemu_irqs which
> the callers then leak.  (The leak is trivial because it happens once
> when QEMU starts.)
>
> The patchseries converts the UIC to a QOM device but initially leaves
> the old ppcuic_init() creation function with its old API intact.  It
> then goes through converting the various boards that were using
> ppcuic_init() to instead directly create the UIC using the usual qdev
> APIs, so that it can delete the ppcuic_init() function entirely.
>
> The patchset includes one patch which deletes 350 lines of dead code
> -- the ppc405cr_init() function seems to have never been used since
> it was added in 2007, so rather than converting this user of
> ppcuic_init() it seemed more sensible to delete it.
>
> I have tested with 'make check' and 'make check-acceptance' but I
> don't think the latter really exercises the affected boards, which
> are:
>
> bamboo
> ref405ep
> sam460ex
> taihu
> virtex-ml507

Thanks to Thomas, commit 99b336cdd90 added check for sam460ex but that 
only checks it the firmware runs.

> I found instructions on how to boot an AROS image on sam460ex, so I
> have tested that: it works as well after this series as it did before
> (gets to "Libs/workbench.library" and stops); it does seem to

That seems to be a problem with AROS that nobody noticed yet. I've 
reported it to them but there seems to be nobody maintaining the PPC 
version, AROS is mostly focused on m86k, ARM and x86. On PPC AmigaOS and 
MorphOS seem to be more popular. I have an AROS test image I've build back 
in 2018 that still works, I'll send it off-list.

> successfully do things like scanning the USB bus and responding to
> keyboard input at the boot menu, which suggests that IRQs must be
> working.

Interestingly the firmware does not use irqs at all, it just polls for 
them it seems. AROS and AmigaOS does seem to break though. With AROS I get 
this exception after your series but it's not very helpful:

[KRN] Exception 0 handler. Context @ ff7ffb28, SysBase @ 00a60410, KernelBase @ 01000154
[KRN] SRR0=ff9e3d78, SRR1=0002f000 DEAR=00000000 ESR=00000000
[KRN] CTR=ff9e48dc LR=ff9e2db4 XER=20000000 CCR=40000848
[KRN] DAR=00000000 DSISR=00000000
[KRN] GPR00=00000006 GPR01=01075d10 GPR02=00a60410 GPR03=00000000
[KRN] GPR04=00000001 GPR05=00000001 GPR06=010538b4 GPR07=ff9e48dc
[KRN] GPR08=01000000 GPR09=00000054 GPR10=ef000000 GPR11=00000001
[KRN] GPR12=40000844 GPR13=00000000 GPR14=00000000 GPR15=00000000
[KRN] GPR16=00000000 GPR17=00000000 GPR18=00000000 GPR19=00000000
[KRN] GPR20=00000000 GPR21=00000000 GPR22=00000000 GPR23=0106bde0
[KRN] GPR24=00031000 GPR25=010596e0 GPR26=01058980 GPR27=ff7f0000
[KRN] GPR28=010596b8 GPR29=0105a0a8 GPR30=01053770 GPR31=01076564
[KRN] Instruction dump:
[KRN] ff9e3d78: 80010064 82e1003c 83010040 7c0803a6
[KRN] ff9e3d88: 83210044 83410048 8361004c 83810050
[KRN] Stackdump:
[KRN] 01075d10: 01075d70 010596e0 09021900 010103c0
[KRN] 01075d20: 00090400 00010900 00040705 81030800
[KRN] 01075d30: 01075d50 ff7f0000 0000ffff 0105a0d8
[KRN] 01075d40: 01075d60 ff9ea1cc 000000ff 0106bde0
[KRN] 01075d50: 00031000 010596e0 01058980 ff7f0000
[KRN] 01075d60: 010596b8 0105a0a8 01053770 0105a0d8
[KRN] 01075d70: 01075d80 ff9e2db4 01059448 ff7f7858
[KRN] 01075d80: 01075e30 ff9e9418 80004722 01075dfc
[KRN] 01075d90: 80004721 01075df8 80004725 01075df4
[KRN] 01075da0: 80004723 01075dec 80004724 01075de8
[KRN] 01075db0: 80004726 01075df0 80004731 01075de4
[KRN] 01075dc0: 80004732 01075de0 00000000 00000000
[KRN] 01075dd0: 00000000 00000000 00000000 00000000
[KRN] 01075de0: 00000001 00000220 00000003 00000001
[KRN] 01075df0: ff9e8568 ff9e8530 ff9e8520 01076738
[KRN] 01075e00: 00000000 00000000 00000000 00000000
[KRN] Backtrace:  Devs/USBHardware/pciusb.device cmdControlXFerRootHub+0xd8
[KRN] LR=ff9e2db4 Devs/USBHardware/pciusb.device pciusb_5_devBeginIO+0x148
[KRN]    ff9e2db4 Devs/USBHardware/pciusb.device pciusb_5_devBeginIO+0x148
[KRN]    ff9e9418 Libs/poseidon.library pDeviceTask+0x5c8
[KRN]    ff845edc boot/sam440/kernel Exec_2_close+0x18
SAD(-1,-1)>

AmigaOS also fails to boot but could not get useful logs from it yet so 
not sure what could be broken.

Regards,
BALATON Zoltan

> Side note: the 'irq_inputs' hacks in the PPC CPU I think would really
> benefit from conversion to being qdev gpio inputs now that CPUs are
> real devices. There are also a lot of non-QOM devices in this
> ppc4xx code if anybody is interested in working on more QOM
> conversions for these boards.
>
> thanks
> -- PMM
>
> Peter Maydell (8):
>  hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
>  ppc: Convert PPC UIC to a QOM device
>  hw/ppc/virtex_ml507: Drop use of ppcuic_init()
>  hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
>  hw/ppc/sam460ex: Drop use of ppcuic_init()
>  hw/ppc: Delete unused ppc405cr_init() code
>  hw/ppc/ppc405_uc: Drop use of ppcuic_init()
>  hw/ppc: Remove unused ppcuic_init()
>
> hw/ppc/ppc405.h           |   8 +-
> include/hw/intc/ppc-uic.h |  80 ++++++++
> include/hw/ppc/ppc4xx.h   |   9 -
> hw/intc/ppc-uic.c         | 321 +++++++++++++++++++++++++++++
> hw/ppc/ppc405_boards.c    |   8 +-
> hw/ppc/ppc405_uc.c        | 415 ++++----------------------------------
> hw/ppc/ppc440_bamboo.c    |  38 +++-
> hw/ppc/ppc4xx_devs.c      | 246 +---------------------
> hw/ppc/sam460ex.c         |  70 +++++--
> hw/ppc/virtex_ml507.c     |  21 +-
> MAINTAINERS               |   2 +
> hw/intc/Kconfig           |   3 +
> hw/intc/meson.build       |   1 +
> hw/ppc/Kconfig            |   1 +
> 14 files changed, 555 insertions(+), 668 deletions(-)
> create mode 100644 include/hw/intc/ppc-uic.h
> create mode 100644 hw/intc/ppc-uic.c
>
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12 17:17   ` BALATON Zoltan via
@ 2020-12-12 18:11     ` Peter Maydell
  2020-12-12 20:35       ` BALATON Zoltan via
  0 siblings, 1 reply; 39+ messages in thread
From: Peter Maydell @ 2020-12-12 18:11 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020 at 17:17, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Sat, 12 Dec 2020, Peter Maydell wrote:
> > Switch the sam460ex board to directly creating and configuring the
> > UIC, rather than doing it via the old ppcuic_init() helper function.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> > hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
> > 1 file changed, 54 insertions(+), 16 deletions(-)
>
> More than 3 times as much than before, qdev seems to be overly verbose and
> less readable but if that's the preferred way then be it.

Yeah, the boilerplate is sometimes a bit clunky; but the benefits
come from devices all behaving in the same way, being introspectable,
having support for things like VM state save/load, etc.

> > diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
> > index 14e6583eb0d..9cf7aad3833 100644
> > --- a/hw/ppc/sam460ex.c
> > +++ b/hw/ppc/sam460ex.c
> > @@ -39,6 +39,7 @@
> > #include "hw/usb/hcd-ehci.h"
> > #include "hw/ppc/fdt.h"
> > #include "hw/qdev-properties.h"
> > +#include "hw/intc/ppc-uic.h"
> >
> > #include <libfdt.h>
> >
> > @@ -281,7 +282,6 @@ static void sam460ex_init(MachineState *machine)
> >     hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
> >     hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
> >     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
> > -    qemu_irq *irqs, *uic[4];
> >     PCIBus *pci_bus;
> >     PowerPCCPU *cpu;
> >     CPUPPCState *env;
> > @@ -293,6 +293,9 @@ static void sam460ex_init(MachineState *machine)
> >     struct boot_info *boot_info;
> >     uint8_t *spd_data;
> >     int success;
> > +    qemu_irq mal_irqs[4];
> > +    DeviceState *uic[4];
> > +    int i;
>
> Maybe keep this where it was above instead of moving to the end and keep
> DeviceState *uic[4]; first so the two others that would be removed later
> are next to each other (just to make patches simpler and keep the order of
> variables which may be roughly as they appear below).

Sure, I can do that.

> >     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
> >     env = &cpu->env;
> > @@ -312,13 +315,35 @@ static void sam460ex_init(MachineState *machine)
> >     ppc4xx_plb_init(env);
> >
> >     /* interrupt controllers */
> > -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> > -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> > -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
>
> Unrelated to this, but I wonder why do we need these casts? Could we just
> define env->irq_inputs as qemu_irq array in the first place? It's now void
> ** which according to the comment next to it may be because once it may
> have been used for different implementations but by now maybe it's only
> used for what its name implies? I haven't checked though if it could be
> cleaned up just raising it if anyone's interested to have a look as there
> are such casts at a lot of other places too.

I mentioned this in the cover letter. The irq_inputs stuff seems
to be an old workaround for not being able to have gpio inputs
to the CPU object. Now that CPUs inherit from TYPE_DEVICE, they
can just create gpio inputs like any other device, and this
code would be able to wire them up without having to dig into
the internals of the CPUPPCState structure.

> > -    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
> > -    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
> > -    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
> > -    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
> > +    for (i = 0; i < ARRAY_SIZE(uic); i++) {
> > +        SysBusDevice *sbd;
>
> There's already a SysBusDevice *sbdev; defined for similar cases that you
> could reuse here.
>
> > +        /*
> > +         * Number of the first of the two consecutive IRQ inputs on UIC 0
> > +         * to connect the INT and CINT outputs of UIC n to. The entry
>
> This comment confused me a bit, while it's precise is it possible to say
> it in a simpler way? I think these are how uic[1-3] are cascaded through
> uic[0] similar to how the PICs in a PC are cascaded.

Yes, it's the cascading -- it's saying "which inputs on UIC 0 should
UIC n's outputs connect to". What would be a helpful way to phrase
this more clearly ?

> > +         * for UIC 0 is ignored, because it connects to the CPU.
> > +         */
> > +        const int input_ints[] = { -1, 30, 10, 16 };

> >     /* MAL */
> > -    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
> > +    /*
> > +     * TODO if the MAL were a proper QOM device we would not need to
> > +     * copy its qemu_irqs into an array for ppc4xx_mal_init()'s benefit.
> > +     */
>
> It's not a todo for sam460ex so maybe put it in the file where mal is if
> you want to note it somewhere? (Other sites using the mal may also need
> updating not just this one when this is cleaned up.)

Yeah. I discovered later that one of the other files that creates
the MAL is doing exactly the same thing with a local mal_irqs[]
type array. So I think we could just drop this TODO comment.
As and when somebody QOMifies the MAL device they'll naturally
come back and fix up all the callsites.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/8] hw/ppc: Convert UIC device to QOM
  2020-12-12 17:43 ` [PATCH 0/8] hw/ppc: Convert UIC device to QOM BALATON Zoltan via
@ 2020-12-12 18:13   ` Peter Maydell
  0 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12 18:13 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020 at 17:43, BALATON Zoltan <balaton@eik.bme.hu> wrote:
> Interestingly the firmware does not use irqs at all, it just polls for
> them it seems. AROS and AmigaOS does seem to break though. With AROS I get
> this exception after your series but it's not very helpful:

> AmigaOS also fails to boot but could not get useful logs from it yet so
> not sure what could be broken.

Thanks for testing this. Do you have pointers to images
and command lines that I can use to reproduce the failure so
I can debug ?

-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
  2020-12-12 16:57   ` BALATON Zoltan via
@ 2020-12-12 18:27   ` BALATON Zoltan via
  2020-12-12 18:33     ` Peter Maydell
  2020-12-13 14:34   ` Edgar E. Iglesias
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 18:27 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

[-- Attachment #1: Type: text/plain, Size: 25237 bytes --]

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> in hw/intc.
>
> The ppcuic_init() function is retained for the moment with its current
> interface; in subsequent commits this will be tidied up to avoid the
> allocation of an irq array.
>
> This conversion adds VMState support.
>
> It leaves the LOG_UIC() macro as-is to maximise the extent to which
> this is simply code-movement rather than a rewrite (in new code it
> would be better to use tracepoints).
>
> The default property values for dcr-base and use-vectors are set to
> match those use by most of our boards with a UIC.

Would this be easier to review if it's split into two patches, first doing 
the conversion in place, then another just doing code moving? Maybe we 
could spot some problem that way easier?

Regards,
BALATON Zoltan

> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> include/hw/intc/ppc-uic.h |  73 +++++++++
> hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
> hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
> MAINTAINERS               |   2 +
> hw/intc/Kconfig           |   3 +
> hw/intc/meson.build       |   1 +
> hw/ppc/Kconfig            |   1 +
> 7 files changed, 431 insertions(+), 237 deletions(-)
> create mode 100644 include/hw/intc/ppc-uic.h
> create mode 100644 hw/intc/ppc-uic.c
>
> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> new file mode 100644
> index 00000000000..e614e2ffd80
> --- /dev/null
> +++ b/include/hw/intc/ppc-uic.h
> @@ -0,0 +1,73 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_INTC_PPC_UIC_H
> +#define HW_INTC_PPC_UIC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_PPC_UIC "ppc-uic"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
> +
> +/*
> + * QEMU interface:
> + * QOM property "cpu": link to the PPC CPU
> + *    (no default, must be set)
> + * QOM property "dcr-base": base of the bank of DCR registers for the UIC
> + *    (default 0x30)
> + * QOM property "use-vectors": true if the UIC has vector registers
> + *    (default true)
> + * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
> + * sysbus IRQs:
> + *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
> + *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
> + */
> +
> +#define UIC_MAX_IRQ 32
> +
> +struct PPCUIC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +    qemu_irq output_cint;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    uint32_t dcr_base;
> +    bool use_vectors;
> +
> +    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> +    uint32_t uicsr;  /* Status register */
> +    uint32_t uicer;  /* Enable register */
> +    uint32_t uiccr;  /* Critical register */
> +    uint32_t uicpr;  /* Polarity register */
> +    uint32_t uictr;  /* Triggering register */
> +    uint32_t uicvcr; /* Vector configuration register */
> +    uint32_t uicvr;
> +};
> +
> +#endif
> diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
> new file mode 100644
> index 00000000000..b21951eea83
> --- /dev/null
> +++ b/hw/intc/ppc-uic.c
> @@ -0,0 +1,321 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "include/hw/intc/ppc-uic.h"
> +#include "hw/irq.h"
> +#include "cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +
> +enum {
> +    DCR_UICSR  = 0x000,
> +    DCR_UICSRS = 0x001,
> +    DCR_UICER  = 0x002,
> +    DCR_UICCR  = 0x003,
> +    DCR_UICPR  = 0x004,
> +    DCR_UICTR  = 0x005,
> +    DCR_UICMSR = 0x006,
> +    DCR_UICVR  = 0x007,
> +    DCR_UICVCR = 0x008,
> +    DCR_UICMAX = 0x009,
> +};
> +
> +/*#define DEBUG_UIC*/
> +
> +#ifdef DEBUG_UIC
> +#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
> +#else
> +#  define LOG_UIC(...) do { } while (0)
> +#endif
> +
> +static void ppcuic_trigger_irq(PPCUIC *uic)
> +{
> +    uint32_t ir, cr;
> +    int start, end, inc, i;
> +
> +    /* Trigger interrupt if any is pending */
> +    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> +    cr = uic->uicsr & uic->uicer & uic->uiccr;
> +    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> +                " uiccr %08" PRIx32 "\n"
> +                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> +                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> +                uic->uicsr & uic->uicer, ir, cr);
> +    if (ir != 0x0000000) {
> +        LOG_UIC("Raise UIC interrupt\n");
> +        qemu_irq_raise(uic->output_int);
> +    } else {
> +        LOG_UIC("Lower UIC interrupt\n");
> +        qemu_irq_lower(uic->output_int);
> +    }
> +    /* Trigger critical interrupt if any is pending and update vector */
> +    if (cr != 0x0000000) {
> +        qemu_irq_raise(uic->output_cint);
> +        if (uic->use_vectors) {
> +            /* Compute critical IRQ vector */
> +            if (uic->uicvcr & 1) {
> +                start = 31;
> +                end = 0;
> +                inc = -1;
> +            } else {
> +                start = 0;
> +                end = 31;
> +                inc = 1;
> +            }
> +            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> +            for (i = start; i <= end; i += inc) {
> +                if (cr & (1 << i)) {
> +                    uic->uicvr += (i - start) * 512 * inc;
> +                    break;
> +                }
> +            }
> +        }
> +        LOG_UIC("Raise UIC critical interrupt - "
> +                    "vector %08" PRIx32 "\n", uic->uicvr);
> +    } else {
> +        LOG_UIC("Lower UIC critical interrupt\n");
> +        qemu_irq_lower(uic->output_cint);
> +        uic->uicvr = 0x00000000;
> +    }
> +}
> +
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    PPCUIC *uic;
> +    uint32_t mask, sr;
> +
> +    uic = opaque;
> +    mask = 1U << (31 - irq_num);
> +    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> +                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> +                __func__, irq_num, level,
> +                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> +    if (irq_num < 0 || irq_num > 31) {
> +        return;
> +    }
> +    sr = uic->uicsr;
> +
> +    /* Update status register */
> +    if (uic->uictr & mask) {
> +        /* Edge sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +        }
> +    } else {
> +        /* Level sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +            uic->level |= mask;
> +        } else {
> +            uic->uicsr &= ~mask;
> +            uic->level &= ~mask;
> +        }
> +    }
> +    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> +                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> +    if (sr != uic->uicsr) {
> +        ppcuic_trigger_irq(uic);
> +    }
> +}
> +
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
> +{
> +    PPCUIC *uic;
> +    uint32_t ret;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +    case DCR_UICSRS:
> +        ret = uic->uicsr;
> +        break;
> +    case DCR_UICER:
> +        ret = uic->uicer;
> +        break;
> +    case DCR_UICCR:
> +        ret = uic->uiccr;
> +        break;
> +    case DCR_UICPR:
> +        ret = uic->uicpr;
> +        break;
> +    case DCR_UICTR:
> +        ret = uic->uictr;
> +        break;
> +    case DCR_UICMSR:
> +        ret = uic->uicsr & uic->uicer;
> +        break;
> +    case DCR_UICVR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvr;
> +        break;
> +    case DCR_UICVCR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvcr;
> +        break;
> +    default:
> +    no_read:
> +        ret = 0x00000000;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPCUIC *uic;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +        uic->uicsr &= ~val;
> +        uic->uicsr |= uic->level;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICSRS:
> +        uic->uicsr |= val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICER:
> +        uic->uicer = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICCR:
> +        uic->uiccr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICPR:
> +        uic->uicpr = val;
> +        break;
> +    case DCR_UICTR:
> +        uic->uictr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICMSR:
> +        break;
> +    case DCR_UICVR:
> +        break;
> +    case DCR_UICVCR:
> +        uic->uicvcr = val & 0xFFFFFFFD;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    }
> +}
> +
> +static void ppc_uic_reset(DeviceState *dev)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +
> +    uic->uiccr = 0x00000000;
> +    uic->uicer = 0x00000000;
> +    uic->uicpr = 0x00000000;
> +    uic->uicsr = 0x00000000;
> +    uic->uictr = 0x00000000;
> +    if (uic->use_vectors) {
> +        uic->uicvcr = 0x00000000;
> +        uic->uicvr = 0x0000000;
> +    }
> +}
> +
> +static void ppc_uic_realize(DeviceState *dev, Error **errp)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    PowerPCCPU *cpu;
> +    int i;
> +
> +    if (!uic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "ppc-uic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    cpu = POWERPC_CPU(uic->cpu);
> +    for (i = 0; i < DCR_UICMAX; i++) {
> +        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
> +                         &dcr_read_uic, &dcr_write_uic);
> +    }
> +
> +    sysbus_init_irq(sbd, &uic->output_int);
> +    sysbus_init_irq(sbd, &uic->output_cint);
> +    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
> +}
> +
> +static Property ppc_uic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
> +    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription ppc_uic_vmstate = {
> +    .name = "ppc-uic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, PPCUIC),
> +        VMSTATE_UINT32(uicsr, PPCUIC),
> +        VMSTATE_UINT32(uicer, PPCUIC),
> +        VMSTATE_UINT32(uiccr, PPCUIC),
> +        VMSTATE_UINT32(uicpr, PPCUIC),
> +        VMSTATE_UINT32(uictr, PPCUIC),
> +        VMSTATE_UINT32(uicvcr, PPCUIC),
> +        VMSTATE_UINT32(uicvr, PPCUIC),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void ppc_uic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ppc_uic_reset;
> +    dc->realize = ppc_uic_realize;
> +    dc->vmsd = &ppc_uic_vmstate;
> +    device_class_set_props(dc, ppc_uic_properties);
> +}
> +
> +static const TypeInfo ppc_uic_info = {
> +    .name = TYPE_PPC_UIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PPCUIC),
> +    .class_init = ppc_uic_class_init,
> +};
> +
> +static void ppc_uic_register_types(void)
> +{
> +    type_register_static(&ppc_uic_info);
> +}
> +
> +type_init(ppc_uic_register_types);
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f2f9ca4ffec..ffe4cf43e88 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -30,9 +30,12 @@
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/ppc4xx.h"
> #include "hw/boards.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> #include "qemu/log.h"
> #include "exec/address-spaces.h"
> #include "qemu/error-report.h"
> +#include "qapi/error.h"
>
> /*#define DEBUG_UIC*/
>
> @@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>
> /*****************************************************************************/
> /* "Universal" Interrupt controller */
> -enum {
> -    DCR_UICSR  = 0x000,
> -    DCR_UICSRS = 0x001,
> -    DCR_UICER  = 0x002,
> -    DCR_UICCR  = 0x003,
> -    DCR_UICPR  = 0x004,
> -    DCR_UICTR  = 0x005,
> -    DCR_UICMSR = 0x006,
> -    DCR_UICVR  = 0x007,
> -    DCR_UICVCR = 0x008,
> -    DCR_UICMAX = 0x009,
> -};
> -
> -#define UIC_MAX_IRQ 32
> -typedef struct ppcuic_t ppcuic_t;
> -struct ppcuic_t {
> -    uint32_t dcr_base;
> -    int use_vectors;
> -    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> -    uint32_t uicsr;  /* Status register */
> -    uint32_t uicer;  /* Enable register */
> -    uint32_t uiccr;  /* Critical register */
> -    uint32_t uicpr;  /* Polarity register */
> -    uint32_t uictr;  /* Triggering register */
> -    uint32_t uicvcr; /* Vector configuration register */
> -    uint32_t uicvr;
> -    qemu_irq *irqs;
> -};
> -
> -static void ppcuic_trigger_irq(ppcuic_t *uic)
> -{
> -    uint32_t ir, cr;
> -    int start, end, inc, i;
> -
> -    /* Trigger interrupt if any is pending */
> -    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> -    cr = uic->uicsr & uic->uicer & uic->uiccr;
> -    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> -                " uiccr %08" PRIx32 "\n"
> -                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> -                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> -                uic->uicsr & uic->uicer, ir, cr);
> -    if (ir != 0x0000000) {
> -        LOG_UIC("Raise UIC interrupt\n");
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    } else {
> -        LOG_UIC("Lower UIC interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    }
> -    /* Trigger critical interrupt if any is pending and update vector */
> -    if (cr != 0x0000000) {
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        if (uic->use_vectors) {
> -            /* Compute critical IRQ vector */
> -            if (uic->uicvcr & 1) {
> -                start = 31;
> -                end = 0;
> -                inc = -1;
> -            } else {
> -                start = 0;
> -                end = 31;
> -                inc = 1;
> -            }
> -            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> -            for (i = start; i <= end; i += inc) {
> -                if (cr & (1 << i)) {
> -                    uic->uicvr += (i - start) * 512 * inc;
> -                    break;
> -                }
> -            }
> -        }
> -        LOG_UIC("Raise UIC critical interrupt - "
> -                    "vector %08" PRIx32 "\n", uic->uicvr);
> -    } else {
> -        LOG_UIC("Lower UIC critical interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        uic->uicvr = 0x00000000;
> -    }
> -}
> -
> -static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> -{
> -    ppcuic_t *uic;
> -    uint32_t mask, sr;
> -
> -    uic = opaque;
> -    mask = 1U << (31 - irq_num);
> -    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> -                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> -                __func__, irq_num, level,
> -                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31) {
> -        return;
> -    }
> -    sr = uic->uicsr;
> -
> -    /* Update status register */
> -    if (uic->uictr & mask) {
> -        /* Edge sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -        }
> -    } else {
> -        /* Level sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -            uic->level |= mask;
> -        } else {
> -            uic->uicsr &= ~mask;
> -            uic->level &= ~mask;
> -        }
> -    }
> -    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> -                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr) {
> -        ppcuic_trigger_irq(uic);
> -    }
> -}
> -
> -static uint32_t dcr_read_uic(void *opaque, int dcrn)
> -{
> -    ppcuic_t *uic;
> -    uint32_t ret;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -    case DCR_UICSRS:
> -        ret = uic->uicsr;
> -        break;
> -    case DCR_UICER:
> -        ret = uic->uicer;
> -        break;
> -    case DCR_UICCR:
> -        ret = uic->uiccr;
> -        break;
> -    case DCR_UICPR:
> -        ret = uic->uicpr;
> -        break;
> -    case DCR_UICTR:
> -        ret = uic->uictr;
> -        break;
> -    case DCR_UICMSR:
> -        ret = uic->uicsr & uic->uicer;
> -        break;
> -    case DCR_UICVR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvr;
> -        break;
> -    case DCR_UICVCR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvcr;
> -        break;
> -    default:
> -    no_read:
> -        ret = 0x00000000;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -        uic->uicsr &= ~val;
> -        uic->uicsr |= uic->level;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICSRS:
> -        uic->uicsr |= val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICER:
> -        uic->uicer = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICCR:
> -        uic->uiccr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICPR:
> -        uic->uicpr = val;
> -        break;
> -    case DCR_UICTR:
> -        uic->uictr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICMSR:
> -        break;
> -    case DCR_UICVR:
> -        break;
> -    case DCR_UICVCR:
> -        uic->uicvcr = val & 0xFFFFFFFD;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    }
> -}
> -
> -static void ppcuic_reset (void *opaque)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    uic->uiccr = 0x00000000;
> -    uic->uicer = 0x00000000;
> -    uic->uicpr = 0x00000000;
> -    uic->uicsr = 0x00000000;
> -    uic->uictr = 0x00000000;
> -    if (uic->use_vectors) {
> -        uic->uicvcr = 0x00000000;
> -        uic->uicvr = 0x0000000;
> -    }
> -}
>
> qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
>                        uint32_t dcr_base, int has_ssr, int has_vr)
> {
> -    ppcuic_t *uic;
> +    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> +    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> +    qemu_irq *uic_irqs;
>     int i;
>
> -    uic = g_malloc0(sizeof(ppcuic_t));
> -    uic->dcr_base = dcr_base;
> -    uic->irqs = irqs;
> -    if (has_vr)
> -        uic->use_vectors = 1;
> -    for (i = 0; i < DCR_UICMAX; i++) {
> -        ppc_dcr_register(env, dcr_base + i, uic,
> -                         &dcr_read_uic, &dcr_write_uic);
> -    }
> -    qemu_register_reset(ppcuic_reset, uic);
> +    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> +    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
>
> -    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> +
> +    /*
> +     * Return an allocated array of the UIC's input IRQ lines.
> +     * This is an ugly temporary API to retain compatibility with
> +     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> +     * None of the callers free this array, so it is leaked -- but
> +     * so was the array allocated by qemu_allocate_irqs() in the
> +     * old code.
> +     *
> +     * The callers should just instantiate the UIC and wire it up
> +     * themselves rather than passing qemu_irq* in and out of this function.
> +     */
> +    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> +    for (i = 0; i < UIC_MAX_IRQ; i++) {
> +        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> +    }
> +    return uic_irqs;
> }
>
> /*****************************************************************************/
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa39490a244..24218800b16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
> F: hw/i2c/ppc4xx_i2c.c
> F: include/hw/ppc/ppc4xx.h
> F: include/hw/i2c/ppc4xx_i2c.h
> +F: hw/intc/ppc-uic.c
> +F: include/hw/intc/ppc-uic.h
>
> Character devices
> M: Marc-André Lureau <marcandre.lureau@redhat.com>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index d07954086a5..468d548ca77 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,6 +62,9 @@ config S390_FLIC_KVM
> config OMPIC
>     bool
>
> +config PPC_UIC
> +    bool
> +
> config RX_ICU
>     bool
>
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 3f82cc230ad..d7dadbe5034 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
> specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
> specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
> specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
> +specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
> specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
> specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index dd86e664d21..982d55f5875 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -53,6 +53,7 @@ config PPC4XX
>     bool
>     select BITBANG_I2C
>     select PCI
> +    select PPC_UIC
>
> config SAM460EX
>     bool
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12 18:27   ` BALATON Zoltan via
@ 2020-12-12 18:33     ` Peter Maydell
  2020-12-12 19:53       ` BALATON Zoltan via
  0 siblings, 1 reply; 39+ messages in thread
From: Peter Maydell @ 2020-12-12 18:33 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020 at 18:27, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Sat, 12 Dec 2020, Peter Maydell wrote:
> > Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> > as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> > in hw/intc.
> >
> > The ppcuic_init() function is retained for the moment with its current
> > interface; in subsequent commits this will be tidied up to avoid the
> > allocation of an irq array.
> >
> > This conversion adds VMState support.
> >
> > It leaves the LOG_UIC() macro as-is to maximise the extent to which
> > this is simply code-movement rather than a rewrite (in new code it
> > would be better to use tracepoints).
> >
> > The default property values for dcr-base and use-vectors are set to
> > match those use by most of our boards with a UIC.
>
> Would this be easier to review if it's split into two patches, first doing
> the conversion in place, then another just doing code moving? Maybe we
> could spot some problem that way easier?

That didn't really feel very feasible to me. You can see that
mostly it's code motion using the git diff --color-moved option
if you look at the commit.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 5/8] hw/ppc/sam460ex: " Peter Maydell
  2020-12-12 17:17   ` BALATON Zoltan via
@ 2020-12-12 19:53   ` BALATON Zoltan via
  2020-12-12 19:55     ` Peter Maydell
  1 sibling, 1 reply; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 19:53 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Switch the sam460ex board to directly creating and configuring the
> UIC, rather than doing it via the old ppcuic_init() helper function.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 54 insertions(+), 16 deletions(-)
>
> diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
> index 14e6583eb0d..9cf7aad3833 100644
> --- a/hw/ppc/sam460ex.c
> +++ b/hw/ppc/sam460ex.c
> @@ -39,6 +39,7 @@
> #include "hw/usb/hcd-ehci.h"
> #include "hw/ppc/fdt.h"
> #include "hw/qdev-properties.h"
> +#include "hw/intc/ppc-uic.h"
>
> #include <libfdt.h>
>
> @@ -281,7 +282,6 @@ static void sam460ex_init(MachineState *machine)
>     hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
>     hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
>     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
> -    qemu_irq *irqs, *uic[4];
>     PCIBus *pci_bus;
>     PowerPCCPU *cpu;
>     CPUPPCState *env;
> @@ -293,6 +293,9 @@ static void sam460ex_init(MachineState *machine)
>     struct boot_info *boot_info;
>     uint8_t *spd_data;
>     int success;
> +    qemu_irq mal_irqs[4];
> +    DeviceState *uic[4];
> +    int i;
>
>     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>     env = &cpu->env;
> @@ -312,13 +315,35 @@ static void sam460ex_init(MachineState *machine)
>     ppc4xx_plb_init(env);
>
>     /* interrupt controllers */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
> -    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
> -    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
> -    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
> +    for (i = 0; i < ARRAY_SIZE(uic); i++) {
> +        SysBusDevice *sbd;
> +        /*
> +         * Number of the first of the two consecutive IRQ inputs on UIC 0
> +         * to connect the INT and CINT outputs of UIC n to. The entry
> +         * for UIC 0 is ignored, because it connects to the CPU.
> +         */
> +        const int input_ints[] = { -1, 30, 10, 16 };
> +
> +        uic[i] = qdev_new(TYPE_PPC_UIC);
> +        sbd = SYS_BUS_DEVICE(uic[i]);
> +
> +        qdev_prop_set_uint32(uic[i], "dcr-base", 0xc0 + i * 0x10);
> +        object_property_set_link(OBJECT(uic[i]), "cpu", OBJECT(cpu),
> +                                 &error_fatal);
> +        sysbus_realize_and_unref(sbd, &error_fatal);
> +
> +        if (i == 0) {
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
> +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +        } else {
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> +                               qdev_get_gpio_in(uic[0], input_ints[i]));
> +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,

OK got it, there's a typo here, this one should be CINT, with that it 
seems to work better.

Regards,
BALATON Zoltan

> +                               qdev_get_gpio_in(uic[0], input_ints[i] + 1));
> +        }
> +    }
>
>     /* SDRAM controller */
>     /* put all RAM on first bank because board has one slot
> @@ -331,7 +356,8 @@ static void sam460ex_init(MachineState *machine)
>                       ram_bases, ram_sizes, 1);
>
>     /* IIC controllers and devices */
> -    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700,
> +                               qdev_get_gpio_in(uic[0], 2));
>     i2c = PPC4xx_I2C(dev)->bus;
>     /* SPD EEPROM on RAM module */
>     spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2,
> @@ -341,7 +367,8 @@ static void sam460ex_init(MachineState *machine)
>     /* RTC */
>     i2c_slave_create_simple(i2c, "m41t80", 0x68);
>
> -    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800,
> +                               qdev_get_gpio_in(uic[0], 3));
>
>     /* External bus controller */
>     ppc405_ebc_init(env);
> @@ -356,7 +383,14 @@ static void sam460ex_init(MachineState *machine)
>     ppc4xx_sdr_init(env);
>
>     /* MAL */
> -    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
> +    /*
> +     * TODO if the MAL were a proper QOM device we would not need to
> +     * copy its qemu_irqs into an array for ppc4xx_mal_init()'s benefit.
> +     */
> +    for (i = 0; i < ARRAY_SIZE(mal_irqs); i++) {
> +        mal_irqs[0] = qdev_get_gpio_in(uic[2], 3 + i);
> +    }
> +    ppc4xx_mal_init(env, 4, 16, mal_irqs);
>
>     /* DMA */
>     ppc4xx_dma_init(env, 0x200);
> @@ -369,21 +403,23 @@ static void sam460ex_init(MachineState *machine)
>     memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
>
>     /* USB */
> -    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
> +    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400,
> +                         qdev_get_gpio_in(uic[2], 29));
>     dev = qdev_new("sysbus-ohci");
>     qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
>     qdev_prop_set_uint32(dev, "num-ports", 6);
>     sbdev = SYS_BUS_DEVICE(dev);
>     sysbus_realize_and_unref(sbdev, &error_fatal);
>     sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
> -    sysbus_connect_irq(sbdev, 0, uic[2][30]);
> +    sysbus_connect_irq(sbdev, 0, qdev_get_gpio_in(uic[2], 30));
>     usb_create_simple(usb_bus_find(-1), "usb-kbd");
>     usb_create_simple(usb_bus_find(-1), "usb-mouse");
>
>     /* PCI bus */
>     ppc460ex_pcie_init(env);
>     /* All PCI irqs are connected to the same UIC pin (cf. UBoot source) */
> -    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000, uic[1][0]);
> +    dev = sysbus_create_simple("ppc440-pcix-host", 0xc0ec00000,
> +                               qdev_get_gpio_in(uic[1], 0));
>     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>     if (!pci_bus) {
>         error_report("couldn't create PCI controller!");
> @@ -405,12 +441,14 @@ static void sam460ex_init(MachineState *machine)
>     /* SoC has 4 UARTs
>      * but board has only one wired and two are present in fdt */
>     if (serial_hd(0) != NULL) {
> -        serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
> +        serial_mm_init(address_space_mem, 0x4ef600300, 0,
> +                       qdev_get_gpio_in(uic[1], 1),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
>                        DEVICE_BIG_ENDIAN);
>     }
>     if (serial_hd(1) != NULL) {
> -        serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
> +        serial_mm_init(address_space_mem, 0x4ef600400, 0,
> +                       qdev_get_gpio_in(uic[0], 1),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
>                        DEVICE_BIG_ENDIAN);
>     }
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12 18:33     ` Peter Maydell
@ 2020-12-12 19:53       ` BALATON Zoltan via
  0 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 19:53 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> On Sat, 12 Dec 2020 at 18:27, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> On Sat, 12 Dec 2020, Peter Maydell wrote:
>>> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
>>> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
>>> in hw/intc.
>>>
>>> The ppcuic_init() function is retained for the moment with its current
>>> interface; in subsequent commits this will be tidied up to avoid the
>>> allocation of an irq array.
>>>
>>> This conversion adds VMState support.
>>>
>>> It leaves the LOG_UIC() macro as-is to maximise the extent to which
>>> this is simply code-movement rather than a rewrite (in new code it
>>> would be better to use tracepoints).
>>>
>>> The default property values for dcr-base and use-vectors are set to
>>> match those use by most of our boards with a UIC.
>>
>> Would this be easier to review if it's split into two patches, first doing
>> the conversion in place, then another just doing code moving? Maybe we
>> could spot some problem that way easier?
>
> That didn't really feel very feasible to me. You can see that
> mostly it's code motion using the git diff --color-moved option
> if you look at the commit.

Thanks this helped a bit, at least to confirm the bug is not in here.

Regards,
BALATON Zoltan


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12 19:53   ` BALATON Zoltan via
@ 2020-12-12 19:55     ` Peter Maydell
  0 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-12 19:55 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020 at 19:53, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> On Sat, 12 Dec 2020, Peter Maydell wrote:
> > Switch the sam460ex board to directly creating and configuring the
> > UIC, rather than doing it via the old ppcuic_init() helper function.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> > hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
> > 1 file changed, 54 insertions(+), 16 deletions(-)

> > +        if (i == 0) {
> > +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> > +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> > +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
> > +                               ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> > +        } else {
> > +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
> > +                               qdev_get_gpio_in(uic[0], input_ints[i]));
> > +            sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
>
> OK got it, there's a typo here, this one should be CINT, with that it
> seems to work better.

Oops, yes. Thanks for taking the time to find my bug, I appreciate it.

-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 5/8] hw/ppc/sam460ex: Drop use of ppcuic_init()
  2020-12-12 18:11     ` Peter Maydell
@ 2020-12-12 20:35       ` BALATON Zoltan via
  0 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-12 20:35 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, QEMU Developers, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> On Sat, 12 Dec 2020 at 17:17, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> On Sat, 12 Dec 2020, Peter Maydell wrote:
>>> Switch the sam460ex board to directly creating and configuring the
>>> UIC, rather than doing it via the old ppcuic_init() helper function.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>> hw/ppc/sam460ex.c | 70 ++++++++++++++++++++++++++++++++++++-----------
>>> 1 file changed, 54 insertions(+), 16 deletions(-)
>>
>> More than 3 times as much than before, qdev seems to be overly verbose and
>> less readable but if that's the preferred way then be it.
>
> Yeah, the boilerplate is sometimes a bit clunky; but the benefits
> come from devices all behaving in the same way, being introspectable,
> having support for things like VM state save/load, etc.

And disadvantage is that a typo can easier hide in there as we've just 
seen. Recent changes to simplify object creation did improve boiler plate 
somewhat but gpios still seem to be a bit obscure and hard to use so maybe 
if somebody has some idea to improve it that could help. I have no idea 
how it could be made simpler though. Maybe less verbose names or some 
helpers/macros for common ops that hide the verbosity could help 
readability.

>>> diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
>>> index 14e6583eb0d..9cf7aad3833 100644
>>> --- a/hw/ppc/sam460ex.c
>>> +++ b/hw/ppc/sam460ex.c
>>> @@ -39,6 +39,7 @@
>>> #include "hw/usb/hcd-ehci.h"
>>> #include "hw/ppc/fdt.h"
>>> #include "hw/qdev-properties.h"
>>> +#include "hw/intc/ppc-uic.h"
>>>
>>> #include <libfdt.h>
>>>
>>> @@ -281,7 +282,6 @@ static void sam460ex_init(MachineState *machine)
>>>     hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
>>>     hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
>>>     MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
>>> -    qemu_irq *irqs, *uic[4];
>>>     PCIBus *pci_bus;
>>>     PowerPCCPU *cpu;
>>>     CPUPPCState *env;
>>> @@ -293,6 +293,9 @@ static void sam460ex_init(MachineState *machine)
>>>     struct boot_info *boot_info;
>>>     uint8_t *spd_data;
>>>     int success;
>>> +    qemu_irq mal_irqs[4];
>>> +    DeviceState *uic[4];
>>> +    int i;
>>
>> Maybe keep this where it was above instead of moving to the end and keep
>> DeviceState *uic[4]; first so the two others that would be removed later
>> are next to each other (just to make patches simpler and keep the order of
>> variables which may be roughly as they appear below).
>
> Sure, I can do that.
>
>>>     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>>>     env = &cpu->env;
>>> @@ -312,13 +315,35 @@ static void sam460ex_init(MachineState *machine)
>>>     ppc4xx_plb_init(env);
>>>
>>>     /* interrupt controllers */
>>> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
>>> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
>>> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
>>
>> Unrelated to this, but I wonder why do we need these casts? Could we just
>> define env->irq_inputs as qemu_irq array in the first place? It's now void
>> ** which according to the comment next to it may be because once it may
>> have been used for different implementations but by now maybe it's only
>> used for what its name implies? I haven't checked though if it could be
>> cleaned up just raising it if anyone's interested to have a look as there
>> are such casts at a lot of other places too.
>
> I mentioned this in the cover letter. The irq_inputs stuff seems
> to be an old workaround for not being able to have gpio inputs
> to the CPU object. Now that CPUs inherit from TYPE_DEVICE, they
> can just create gpio inputs like any other device, and this
> code would be able to wire them up without having to dig into
> the internals of the CPUPPCState structure.

Yes, noticed that after I've answered this.

>>> -    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
>>> -    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
>>> -    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
>>> -    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
>>> +    for (i = 0; i < ARRAY_SIZE(uic); i++) {
>>> +        SysBusDevice *sbd;
>>
>> There's already a SysBusDevice *sbdev; defined for similar cases that you
>> could reuse here.
>>
>>> +        /*
>>> +         * Number of the first of the two consecutive IRQ inputs on UIC 0
>>> +         * to connect the INT and CINT outputs of UIC n to. The entry
>>
>> This comment confused me a bit, while it's precise is it possible to say
>> it in a simpler way? I think these are how uic[1-3] are cascaded through
>> uic[0] similar to how the PICs in a PC are cascaded.
>
> Yes, it's the cascading -- it's saying "which inputs on UIC 0 should
> UIC n's outputs connect to". What would be a helpful way to phrase
> this more clearly ?

Hah, you're the native English speaker so I hoped you could reformulate it 
in a simpler way. (But maybe that's what makes it more difficult because 
the current version already makes perfect sense to you.) Maybe something 
like "Interrupt numbers in uic[0] where INT outputs of uic[1]-uic[3] are 
connected for cascading. The CINT output is connected to the next 
interrupt number. The entry for uic[0] is ignored because it connects to 
the CPU."

Regards,
BALATON Zoltan

>>> +         * for UIC 0 is ignored, because it connects to the CPU.
>>> +         */
>>> +        const int input_ints[] = { -1, 30, 10, 16 };
>
>>>     /* MAL */
>>> -    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
>>> +    /*
>>> +     * TODO if the MAL were a proper QOM device we would not need to
>>> +     * copy its qemu_irqs into an array for ppc4xx_mal_init()'s benefit.
>>> +     */
>>
>> It's not a todo for sam460ex so maybe put it in the file where mal is if
>> you want to note it somewhere? (Other sites using the mal may also need
>> updating not just this one when this is cleaned up.)
>
> Yeah. I discovered later that one of the other files that creates
> the MAL is doing exactly the same thing with a local mal_irqs[]
> type array. So I think we could just drop this TODO comment.
> As and when somebody QOMifies the MAL device they'll naturally
> come back and fix up all the callsites.
>
> thanks
> -- PMM
>
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
@ 2020-12-13 12:09   ` Philippe Mathieu-Daudé
  2020-12-13 14:33   ` Edgar E. Iglesias
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-12-13 12:09 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

On 12/12/20 1:15 AM, Peter Maydell wrote:
> In a following commit we will move the PPC UIC implementation to
> its own file in hw/intc. To prevent checkpatch complaining about that
> code-motion, fix up the minor style issues first.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/ppc/ppc4xx_devs.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
@ 2020-12-13 14:32   ` Edgar E. Iglesias
  2020-12-14  5:55   ` David Gibson
  2021-01-11 19:04   ` BALATON Zoltan
  2 siblings, 0 replies; 39+ messages in thread
From: Edgar E. Iglesias @ 2020-12-13 14:32 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, Dec 12, 2020 at 12:15:32AM +0000, Peter Maydell wrote:
> Switch the virtex_ml507 board to directly creating and
> configuring the UIC, rather than doing it via the old
> ppcuic_init() helper function.
> 
> This fixes a trivial Coverity-detected memory leak where
> we were leaking the array of IRQs returned by ppcuic_init().
> 
> Fixes: Coverity CID 1421992
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>



> ---
>  hw/ppc/virtex_ml507.c | 21 ++++++++++++++++-----
>  1 file changed, 16 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
> index 7f1bca928c1..34767b11cad 100644
> --- a/hw/ppc/virtex_ml507.c
> +++ b/hw/ppc/virtex_ml507.c
> @@ -43,6 +43,7 @@
>  #include "qemu/option.h"
>  #include "exec/address-spaces.h"
>  
> +#include "hw/intc/ppc-uic.h"
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/ppc4xx.h"
>  #include "hw/qdev-properties.h"
> @@ -95,7 +96,8 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
>  {
>      PowerPCCPU *cpu;
>      CPUPPCState *env;
> -    qemu_irq *irqs;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>  
>      cpu = POWERPC_CPU(cpu_create(cpu_type));
>      env = &cpu->env;
> @@ -105,10 +107,19 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
>      ppc_dcr_init(env, NULL, NULL);
>  
>      /* interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    ppcuic_init(env, irqs, 0x0C0, 0, 1);
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +
> +    /* This board doesn't wire anything up to the inputs of the UIC. */
>      return cpu;
>  }
>  
> -- 
> 2.20.1
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
  2020-12-13 12:09   ` Philippe Mathieu-Daudé
@ 2020-12-13 14:33   ` Edgar E. Iglesias
  2020-12-14  5:43   ` David Gibson
  2020-12-14  9:15   ` Thomas Huth
  3 siblings, 0 replies; 39+ messages in thread
From: Edgar E. Iglesias @ 2020-12-13 14:33 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, Dec 12, 2020 at 12:15:30AM +0000, Peter Maydell wrote:
> In a following commit we will move the PPC UIC implementation to
> its own file in hw/intc. To prevent checkpatch complaining about that
> code-motion, fix up the minor style issues first.

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>


> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/ppc/ppc4xx_devs.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f1651e04d9a..f2f9ca4ffec 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -105,7 +105,7 @@ struct ppcuic_t {
>      qemu_irq *irqs;
>  };
>  
> -static void ppcuic_trigger_irq (ppcuic_t *uic)
> +static void ppcuic_trigger_irq(ppcuic_t *uic)
>  {
>      uint32_t ir, cr;
>      int start, end, inc, i;
> @@ -156,26 +156,28 @@ static void ppcuic_trigger_irq (ppcuic_t *uic)
>      }
>  }
>  
> -static void ppcuic_set_irq (void *opaque, int irq_num, int level)
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
>  {
>      ppcuic_t *uic;
>      uint32_t mask, sr;
>  
>      uic = opaque;
> -    mask = 1U << (31-irq_num);
> +    mask = 1U << (31 - irq_num);
>      LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
>                  " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
>                  __func__, irq_num, level,
>                  uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31)
> +    if (irq_num < 0 || irq_num > 31) {
>          return;
> +    }
>      sr = uic->uicsr;
>  
>      /* Update status register */
>      if (uic->uictr & mask) {
>          /* Edge sensitive interrupt */
> -        if (level == 1)
> +        if (level == 1) {
>              uic->uicsr |= mask;
> +        }
>      } else {
>          /* Level sensitive interrupt */
>          if (level == 1) {
> @@ -188,11 +190,12 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level)
>      }
>      LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
>                  "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr)
> +    if (sr != uic->uicsr) {
>          ppcuic_trigger_irq(uic);
> +    }
>  }
>  
> -static uint32_t dcr_read_uic (void *opaque, int dcrn)
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
>  {
>      ppcuic_t *uic;
>      uint32_t ret;
> @@ -220,13 +223,15 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
>          ret = uic->uicsr & uic->uicer;
>          break;
>      case DCR_UICVR:
> -        if (!uic->use_vectors)
> +        if (!uic->use_vectors) {
>              goto no_read;
> +        }
>          ret = uic->uicvr;
>          break;
>      case DCR_UICVCR:
> -        if (!uic->use_vectors)
> +        if (!uic->use_vectors) {
>              goto no_read;
> +        }
>          ret = uic->uicvcr;
>          break;
>      default:
> @@ -238,7 +243,7 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
>      return ret;
>  }
>  
> -static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
>  {
>      ppcuic_t *uic;
>  
> -- 
> 2.20.1
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
  2020-12-12 16:57   ` BALATON Zoltan via
  2020-12-12 18:27   ` BALATON Zoltan via
@ 2020-12-13 14:34   ` Edgar E. Iglesias
  2020-12-14  5:54   ` David Gibson
  2020-12-14  9:12   ` BALATON Zoltan via
  4 siblings, 0 replies; 39+ messages in thread
From: Edgar E. Iglesias @ 2020-12-13 14:34 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, Dec 12, 2020 at 12:15:31AM +0000, Peter Maydell wrote:
> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> in hw/intc.
> 
> The ppcuic_init() function is retained for the moment with its current
> interface; in subsequent commits this will be tidied up to avoid the
> allocation of an irq array.
> 
> This conversion adds VMState support.
> 
> It leaves the LOG_UIC() macro as-is to maximise the extent to which
> this is simply code-movement rather than a rewrite (in new code it
> would be better to use tracepoints).
> 
> The default property values for dcr-base and use-vectors are set to
> match those use by most of our boards with a UIC.

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>



> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/intc/ppc-uic.h |  73 +++++++++
>  hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
>  hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
>  MAINTAINERS               |   2 +
>  hw/intc/Kconfig           |   3 +
>  hw/intc/meson.build       |   1 +
>  hw/ppc/Kconfig            |   1 +
>  7 files changed, 431 insertions(+), 237 deletions(-)
>  create mode 100644 include/hw/intc/ppc-uic.h
>  create mode 100644 hw/intc/ppc-uic.c
> 
> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> new file mode 100644
> index 00000000000..e614e2ffd80
> --- /dev/null
> +++ b/include/hw/intc/ppc-uic.h
> @@ -0,0 +1,73 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_INTC_PPC_UIC_H
> +#define HW_INTC_PPC_UIC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_PPC_UIC "ppc-uic"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
> +
> +/*
> + * QEMU interface:
> + * QOM property "cpu": link to the PPC CPU
> + *    (no default, must be set)
> + * QOM property "dcr-base": base of the bank of DCR registers for the UIC
> + *    (default 0x30)
> + * QOM property "use-vectors": true if the UIC has vector registers
> + *    (default true)
> + * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
> + * sysbus IRQs:
> + *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
> + *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
> + */
> +
> +#define UIC_MAX_IRQ 32
> +
> +struct PPCUIC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +    qemu_irq output_cint;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    uint32_t dcr_base;
> +    bool use_vectors;
> +
> +    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> +    uint32_t uicsr;  /* Status register */
> +    uint32_t uicer;  /* Enable register */
> +    uint32_t uiccr;  /* Critical register */
> +    uint32_t uicpr;  /* Polarity register */
> +    uint32_t uictr;  /* Triggering register */
> +    uint32_t uicvcr; /* Vector configuration register */
> +    uint32_t uicvr;
> +};
> +
> +#endif
> diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
> new file mode 100644
> index 00000000000..b21951eea83
> --- /dev/null
> +++ b/hw/intc/ppc-uic.c
> @@ -0,0 +1,321 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "include/hw/intc/ppc-uic.h"
> +#include "hw/irq.h"
> +#include "cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +
> +enum {
> +    DCR_UICSR  = 0x000,
> +    DCR_UICSRS = 0x001,
> +    DCR_UICER  = 0x002,
> +    DCR_UICCR  = 0x003,
> +    DCR_UICPR  = 0x004,
> +    DCR_UICTR  = 0x005,
> +    DCR_UICMSR = 0x006,
> +    DCR_UICVR  = 0x007,
> +    DCR_UICVCR = 0x008,
> +    DCR_UICMAX = 0x009,
> +};
> +
> +/*#define DEBUG_UIC*/
> +
> +#ifdef DEBUG_UIC
> +#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
> +#else
> +#  define LOG_UIC(...) do { } while (0)
> +#endif
> +
> +static void ppcuic_trigger_irq(PPCUIC *uic)
> +{
> +    uint32_t ir, cr;
> +    int start, end, inc, i;
> +
> +    /* Trigger interrupt if any is pending */
> +    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> +    cr = uic->uicsr & uic->uicer & uic->uiccr;
> +    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> +                " uiccr %08" PRIx32 "\n"
> +                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> +                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> +                uic->uicsr & uic->uicer, ir, cr);
> +    if (ir != 0x0000000) {
> +        LOG_UIC("Raise UIC interrupt\n");
> +        qemu_irq_raise(uic->output_int);
> +    } else {
> +        LOG_UIC("Lower UIC interrupt\n");
> +        qemu_irq_lower(uic->output_int);
> +    }
> +    /* Trigger critical interrupt if any is pending and update vector */
> +    if (cr != 0x0000000) {
> +        qemu_irq_raise(uic->output_cint);
> +        if (uic->use_vectors) {
> +            /* Compute critical IRQ vector */
> +            if (uic->uicvcr & 1) {
> +                start = 31;
> +                end = 0;
> +                inc = -1;
> +            } else {
> +                start = 0;
> +                end = 31;
> +                inc = 1;
> +            }
> +            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> +            for (i = start; i <= end; i += inc) {
> +                if (cr & (1 << i)) {
> +                    uic->uicvr += (i - start) * 512 * inc;
> +                    break;
> +                }
> +            }
> +        }
> +        LOG_UIC("Raise UIC critical interrupt - "
> +                    "vector %08" PRIx32 "\n", uic->uicvr);
> +    } else {
> +        LOG_UIC("Lower UIC critical interrupt\n");
> +        qemu_irq_lower(uic->output_cint);
> +        uic->uicvr = 0x00000000;
> +    }
> +}
> +
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    PPCUIC *uic;
> +    uint32_t mask, sr;
> +
> +    uic = opaque;
> +    mask = 1U << (31 - irq_num);
> +    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> +                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> +                __func__, irq_num, level,
> +                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> +    if (irq_num < 0 || irq_num > 31) {
> +        return;
> +    }
> +    sr = uic->uicsr;
> +
> +    /* Update status register */
> +    if (uic->uictr & mask) {
> +        /* Edge sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +        }
> +    } else {
> +        /* Level sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +            uic->level |= mask;
> +        } else {
> +            uic->uicsr &= ~mask;
> +            uic->level &= ~mask;
> +        }
> +    }
> +    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> +                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> +    if (sr != uic->uicsr) {
> +        ppcuic_trigger_irq(uic);
> +    }
> +}
> +
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
> +{
> +    PPCUIC *uic;
> +    uint32_t ret;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +    case DCR_UICSRS:
> +        ret = uic->uicsr;
> +        break;
> +    case DCR_UICER:
> +        ret = uic->uicer;
> +        break;
> +    case DCR_UICCR:
> +        ret = uic->uiccr;
> +        break;
> +    case DCR_UICPR:
> +        ret = uic->uicpr;
> +        break;
> +    case DCR_UICTR:
> +        ret = uic->uictr;
> +        break;
> +    case DCR_UICMSR:
> +        ret = uic->uicsr & uic->uicer;
> +        break;
> +    case DCR_UICVR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvr;
> +        break;
> +    case DCR_UICVCR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvcr;
> +        break;
> +    default:
> +    no_read:
> +        ret = 0x00000000;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPCUIC *uic;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +        uic->uicsr &= ~val;
> +        uic->uicsr |= uic->level;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICSRS:
> +        uic->uicsr |= val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICER:
> +        uic->uicer = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICCR:
> +        uic->uiccr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICPR:
> +        uic->uicpr = val;
> +        break;
> +    case DCR_UICTR:
> +        uic->uictr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICMSR:
> +        break;
> +    case DCR_UICVR:
> +        break;
> +    case DCR_UICVCR:
> +        uic->uicvcr = val & 0xFFFFFFFD;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    }
> +}
> +
> +static void ppc_uic_reset(DeviceState *dev)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +
> +    uic->uiccr = 0x00000000;
> +    uic->uicer = 0x00000000;
> +    uic->uicpr = 0x00000000;
> +    uic->uicsr = 0x00000000;
> +    uic->uictr = 0x00000000;
> +    if (uic->use_vectors) {
> +        uic->uicvcr = 0x00000000;
> +        uic->uicvr = 0x0000000;
> +    }
> +}
> +
> +static void ppc_uic_realize(DeviceState *dev, Error **errp)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    PowerPCCPU *cpu;
> +    int i;
> +
> +    if (!uic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "ppc-uic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    cpu = POWERPC_CPU(uic->cpu);
> +    for (i = 0; i < DCR_UICMAX; i++) {
> +        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
> +                         &dcr_read_uic, &dcr_write_uic);
> +    }
> +
> +    sysbus_init_irq(sbd, &uic->output_int);
> +    sysbus_init_irq(sbd, &uic->output_cint);
> +    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
> +}
> +
> +static Property ppc_uic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
> +    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription ppc_uic_vmstate = {
> +    .name = "ppc-uic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, PPCUIC),
> +        VMSTATE_UINT32(uicsr, PPCUIC),
> +        VMSTATE_UINT32(uicer, PPCUIC),
> +        VMSTATE_UINT32(uiccr, PPCUIC),
> +        VMSTATE_UINT32(uicpr, PPCUIC),
> +        VMSTATE_UINT32(uictr, PPCUIC),
> +        VMSTATE_UINT32(uicvcr, PPCUIC),
> +        VMSTATE_UINT32(uicvr, PPCUIC),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void ppc_uic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ppc_uic_reset;
> +    dc->realize = ppc_uic_realize;
> +    dc->vmsd = &ppc_uic_vmstate;
> +    device_class_set_props(dc, ppc_uic_properties);
> +}
> +
> +static const TypeInfo ppc_uic_info = {
> +    .name = TYPE_PPC_UIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PPCUIC),
> +    .class_init = ppc_uic_class_init,
> +};
> +
> +static void ppc_uic_register_types(void)
> +{
> +    type_register_static(&ppc_uic_info);
> +}
> +
> +type_init(ppc_uic_register_types);
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f2f9ca4ffec..ffe4cf43e88 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -30,9 +30,12 @@
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/ppc4xx.h"
>  #include "hw/boards.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
>  #include "qemu/log.h"
>  #include "exec/address-spaces.h"
>  #include "qemu/error-report.h"
> +#include "qapi/error.h"
>  
>  /*#define DEBUG_UIC*/
>  
> @@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>  
>  /*****************************************************************************/
>  /* "Universal" Interrupt controller */
> -enum {
> -    DCR_UICSR  = 0x000,
> -    DCR_UICSRS = 0x001,
> -    DCR_UICER  = 0x002,
> -    DCR_UICCR  = 0x003,
> -    DCR_UICPR  = 0x004,
> -    DCR_UICTR  = 0x005,
> -    DCR_UICMSR = 0x006,
> -    DCR_UICVR  = 0x007,
> -    DCR_UICVCR = 0x008,
> -    DCR_UICMAX = 0x009,
> -};
> -
> -#define UIC_MAX_IRQ 32
> -typedef struct ppcuic_t ppcuic_t;
> -struct ppcuic_t {
> -    uint32_t dcr_base;
> -    int use_vectors;
> -    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> -    uint32_t uicsr;  /* Status register */
> -    uint32_t uicer;  /* Enable register */
> -    uint32_t uiccr;  /* Critical register */
> -    uint32_t uicpr;  /* Polarity register */
> -    uint32_t uictr;  /* Triggering register */
> -    uint32_t uicvcr; /* Vector configuration register */
> -    uint32_t uicvr;
> -    qemu_irq *irqs;
> -};
> -
> -static void ppcuic_trigger_irq(ppcuic_t *uic)
> -{
> -    uint32_t ir, cr;
> -    int start, end, inc, i;
> -
> -    /* Trigger interrupt if any is pending */
> -    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> -    cr = uic->uicsr & uic->uicer & uic->uiccr;
> -    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> -                " uiccr %08" PRIx32 "\n"
> -                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> -                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> -                uic->uicsr & uic->uicer, ir, cr);
> -    if (ir != 0x0000000) {
> -        LOG_UIC("Raise UIC interrupt\n");
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    } else {
> -        LOG_UIC("Lower UIC interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    }
> -    /* Trigger critical interrupt if any is pending and update vector */
> -    if (cr != 0x0000000) {
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        if (uic->use_vectors) {
> -            /* Compute critical IRQ vector */
> -            if (uic->uicvcr & 1) {
> -                start = 31;
> -                end = 0;
> -                inc = -1;
> -            } else {
> -                start = 0;
> -                end = 31;
> -                inc = 1;
> -            }
> -            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> -            for (i = start; i <= end; i += inc) {
> -                if (cr & (1 << i)) {
> -                    uic->uicvr += (i - start) * 512 * inc;
> -                    break;
> -                }
> -            }
> -        }
> -        LOG_UIC("Raise UIC critical interrupt - "
> -                    "vector %08" PRIx32 "\n", uic->uicvr);
> -    } else {
> -        LOG_UIC("Lower UIC critical interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        uic->uicvr = 0x00000000;
> -    }
> -}
> -
> -static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> -{
> -    ppcuic_t *uic;
> -    uint32_t mask, sr;
> -
> -    uic = opaque;
> -    mask = 1U << (31 - irq_num);
> -    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> -                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> -                __func__, irq_num, level,
> -                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31) {
> -        return;
> -    }
> -    sr = uic->uicsr;
> -
> -    /* Update status register */
> -    if (uic->uictr & mask) {
> -        /* Edge sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -        }
> -    } else {
> -        /* Level sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -            uic->level |= mask;
> -        } else {
> -            uic->uicsr &= ~mask;
> -            uic->level &= ~mask;
> -        }
> -    }
> -    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> -                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr) {
> -        ppcuic_trigger_irq(uic);
> -    }
> -}
> -
> -static uint32_t dcr_read_uic(void *opaque, int dcrn)
> -{
> -    ppcuic_t *uic;
> -    uint32_t ret;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -    case DCR_UICSRS:
> -        ret = uic->uicsr;
> -        break;
> -    case DCR_UICER:
> -        ret = uic->uicer;
> -        break;
> -    case DCR_UICCR:
> -        ret = uic->uiccr;
> -        break;
> -    case DCR_UICPR:
> -        ret = uic->uicpr;
> -        break;
> -    case DCR_UICTR:
> -        ret = uic->uictr;
> -        break;
> -    case DCR_UICMSR:
> -        ret = uic->uicsr & uic->uicer;
> -        break;
> -    case DCR_UICVR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvr;
> -        break;
> -    case DCR_UICVCR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvcr;
> -        break;
> -    default:
> -    no_read:
> -        ret = 0x00000000;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -        uic->uicsr &= ~val;
> -        uic->uicsr |= uic->level;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICSRS:
> -        uic->uicsr |= val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICER:
> -        uic->uicer = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICCR:
> -        uic->uiccr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICPR:
> -        uic->uicpr = val;
> -        break;
> -    case DCR_UICTR:
> -        uic->uictr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICMSR:
> -        break;
> -    case DCR_UICVR:
> -        break;
> -    case DCR_UICVCR:
> -        uic->uicvcr = val & 0xFFFFFFFD;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    }
> -}
> -
> -static void ppcuic_reset (void *opaque)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    uic->uiccr = 0x00000000;
> -    uic->uicer = 0x00000000;
> -    uic->uicpr = 0x00000000;
> -    uic->uicsr = 0x00000000;
> -    uic->uictr = 0x00000000;
> -    if (uic->use_vectors) {
> -        uic->uicvcr = 0x00000000;
> -        uic->uicvr = 0x0000000;
> -    }
> -}
>  
>  qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
>                         uint32_t dcr_base, int has_ssr, int has_vr)
>  {
> -    ppcuic_t *uic;
> +    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> +    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> +    qemu_irq *uic_irqs;
>      int i;
>  
> -    uic = g_malloc0(sizeof(ppcuic_t));
> -    uic->dcr_base = dcr_base;
> -    uic->irqs = irqs;
> -    if (has_vr)
> -        uic->use_vectors = 1;
> -    for (i = 0; i < DCR_UICMAX; i++) {
> -        ppc_dcr_register(env, dcr_base + i, uic,
> -                         &dcr_read_uic, &dcr_write_uic);
> -    }
> -    qemu_register_reset(ppcuic_reset, uic);
> +    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> +    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
>  
> -    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> +
> +    /*
> +     * Return an allocated array of the UIC's input IRQ lines.
> +     * This is an ugly temporary API to retain compatibility with
> +     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> +     * None of the callers free this array, so it is leaked -- but
> +     * so was the array allocated by qemu_allocate_irqs() in the
> +     * old code.
> +     *
> +     * The callers should just instantiate the UIC and wire it up
> +     * themselves rather than passing qemu_irq* in and out of this function.
> +     */
> +    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> +    for (i = 0; i < UIC_MAX_IRQ; i++) {
> +        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> +    }
> +    return uic_irqs;
>  }
>  
>  /*****************************************************************************/
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa39490a244..24218800b16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
>  F: hw/i2c/ppc4xx_i2c.c
>  F: include/hw/ppc/ppc4xx.h
>  F: include/hw/i2c/ppc4xx_i2c.h
> +F: hw/intc/ppc-uic.c
> +F: include/hw/intc/ppc-uic.h
>  
>  Character devices
>  M: Marc-André Lureau <marcandre.lureau@redhat.com>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index d07954086a5..468d548ca77 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,6 +62,9 @@ config S390_FLIC_KVM
>  config OMPIC
>      bool
>  
> +config PPC_UIC
> +    bool
> +
>  config RX_ICU
>      bool
>  
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 3f82cc230ad..d7dadbe5034 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
>  specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
>  specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
> +specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
>  specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
>  specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index dd86e664d21..982d55f5875 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -53,6 +53,7 @@ config PPC4XX
>      bool
>      select BITBANG_I2C
>      select PCI
> +    select PPC_UIC
>  
>  config SAM460EX
>      bool
> -- 
> 2.20.1
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 8/8] hw/ppc: Remove unused ppcuic_init()
  2020-12-12  0:15 ` [PATCH 8/8] hw/ppc: Remove unused ppcuic_init() Peter Maydell
@ 2020-12-13 14:35   ` Edgar E. Iglesias
  0 siblings, 0 replies; 39+ messages in thread
From: Edgar E. Iglesias @ 2020-12-13 14:35 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, Dec 12, 2020 at 12:15:37AM +0000, Peter Maydell wrote:
> Now we've converted all the callsites to directly create the QOM UIC
> device themselves, the ppcuic_init() function is unused and can be
> removed. The enum defining PPCUIC symbolic constants can be moved
> to the ppc-uic.h header where it more naturally belongs.

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>


> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/intc/ppc-uic.h |  7 +++++++
>  include/hw/ppc/ppc4xx.h   |  9 ---------
>  hw/ppc/ppc4xx_devs.c      | 38 --------------------------------------
>  3 files changed, 7 insertions(+), 47 deletions(-)
> 
> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> index e614e2ffd80..22dd5e5ac2c 100644
> --- a/include/hw/intc/ppc-uic.h
> +++ b/include/hw/intc/ppc-uic.h
> @@ -47,6 +47,13 @@ OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
>  
>  #define UIC_MAX_IRQ 32
>  
> +/* Symbolic constants for the sysbus IRQ outputs */
> +enum {
> +    PPCUIC_OUTPUT_INT = 0,
> +    PPCUIC_OUTPUT_CINT = 1,
> +    PPCUIC_OUTPUT_NB,
> +};
> +
>  struct PPCUIC {
>      /*< private >*/
>      SysBusDevice parent_obj;
> diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
> index cc19c8da5be..980f964b5a9 100644
> --- a/include/hw/ppc/ppc4xx.h
> +++ b/include/hw/ppc/ppc4xx.h
> @@ -33,15 +33,6 @@ PowerPCCPU *ppc4xx_init(const char *cpu_model,
>                          clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
>                          uint32_t sysclk);
>  
> -/* PowerPC 4xx universal interrupt controller */
> -enum {
> -    PPCUIC_OUTPUT_INT = 0,
> -    PPCUIC_OUTPUT_CINT = 1,
> -    PPCUIC_OUTPUT_NB,
> -};
> -qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
> -                       uint32_t dcr_base, int has_ssr, int has_vr);
> -
>  void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
>                          MemoryRegion ram_memories[],
>                          hwaddr ram_bases[], hwaddr ram_sizes[],
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index ffe4cf43e88..fe9d4f7155e 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -77,44 +77,6 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>      return cpu;
>  }
>  
> -/*****************************************************************************/
> -/* "Universal" Interrupt controller */
> -
> -qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
> -                       uint32_t dcr_base, int has_ssr, int has_vr)
> -{
> -    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> -    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> -    qemu_irq *uic_irqs;
> -    int i;
> -
> -    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> -    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> -    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> -                             &error_fatal);
> -    sysbus_realize_and_unref(uicsbd, &error_fatal);
> -
> -    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> -    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> -
> -    /*
> -     * Return an allocated array of the UIC's input IRQ lines.
> -     * This is an ugly temporary API to retain compatibility with
> -     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> -     * None of the callers free this array, so it is leaked -- but
> -     * so was the array allocated by qemu_allocate_irqs() in the
> -     * old code.
> -     *
> -     * The callers should just instantiate the UIC and wire it up
> -     * themselves rather than passing qemu_irq* in and out of this function.
> -     */
> -    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> -    for (i = 0; i < UIC_MAX_IRQ; i++) {
> -        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> -    }
> -    return uic_irqs;
> -}
> -
>  /*****************************************************************************/
>  /* SDRAM controller */
>  typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
> -- 
> 2.20.1
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
  2020-12-13 12:09   ` Philippe Mathieu-Daudé
  2020-12-13 14:33   ` Edgar E. Iglesias
@ 2020-12-14  5:43   ` David Gibson
  2020-12-14  9:15   ` Thomas Huth
  3 siblings, 0 replies; 39+ messages in thread
From: David Gibson @ 2020-12-14  5:43 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3516 bytes --]

On Sat, Dec 12, 2020 at 12:15:30AM +0000, Peter Maydell wrote:
> In a following commit we will move the PPC UIC implementation to
> its own file in hw/intc. To prevent checkpatch complaining about that
> code-motion, fix up the minor style issues first.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Applied to ppc-for-6.0, thanks.

> ---
>  hw/ppc/ppc4xx_devs.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f1651e04d9a..f2f9ca4ffec 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -105,7 +105,7 @@ struct ppcuic_t {
>      qemu_irq *irqs;
>  };
>  
> -static void ppcuic_trigger_irq (ppcuic_t *uic)
> +static void ppcuic_trigger_irq(ppcuic_t *uic)
>  {
>      uint32_t ir, cr;
>      int start, end, inc, i;
> @@ -156,26 +156,28 @@ static void ppcuic_trigger_irq (ppcuic_t *uic)
>      }
>  }
>  
> -static void ppcuic_set_irq (void *opaque, int irq_num, int level)
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
>  {
>      ppcuic_t *uic;
>      uint32_t mask, sr;
>  
>      uic = opaque;
> -    mask = 1U << (31-irq_num);
> +    mask = 1U << (31 - irq_num);
>      LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
>                  " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
>                  __func__, irq_num, level,
>                  uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31)
> +    if (irq_num < 0 || irq_num > 31) {
>          return;
> +    }
>      sr = uic->uicsr;
>  
>      /* Update status register */
>      if (uic->uictr & mask) {
>          /* Edge sensitive interrupt */
> -        if (level == 1)
> +        if (level == 1) {
>              uic->uicsr |= mask;
> +        }
>      } else {
>          /* Level sensitive interrupt */
>          if (level == 1) {
> @@ -188,11 +190,12 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level)
>      }
>      LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
>                  "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr)
> +    if (sr != uic->uicsr) {
>          ppcuic_trigger_irq(uic);
> +    }
>  }
>  
> -static uint32_t dcr_read_uic (void *opaque, int dcrn)
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
>  {
>      ppcuic_t *uic;
>      uint32_t ret;
> @@ -220,13 +223,15 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
>          ret = uic->uicsr & uic->uicer;
>          break;
>      case DCR_UICVR:
> -        if (!uic->use_vectors)
> +        if (!uic->use_vectors) {
>              goto no_read;
> +        }
>          ret = uic->uicvr;
>          break;
>      case DCR_UICVCR:
> -        if (!uic->use_vectors)
> +        if (!uic->use_vectors) {
>              goto no_read;
> +        }
>          ret = uic->uicvcr;
>          break;
>      default:
> @@ -238,7 +243,7 @@ static uint32_t dcr_read_uic (void *opaque, int dcrn)
>      return ret;
>  }
>  
> -static void dcr_write_uic (void *opaque, int dcrn, uint32_t val)
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
>  {
>      ppcuic_t *uic;
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
                     ` (2 preceding siblings ...)
  2020-12-13 14:34   ` Edgar E. Iglesias
@ 2020-12-14  5:54   ` David Gibson
  2020-12-14  9:12   ` BALATON Zoltan via
  4 siblings, 0 replies; 39+ messages in thread
From: David Gibson @ 2020-12-14  5:54 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 26131 bytes --]

On Sat, Dec 12, 2020 at 12:15:31AM +0000, Peter Maydell wrote:
> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> in hw/intc.
> 
> The ppcuic_init() function is retained for the moment with its current
> interface; in subsequent commits this will be tidied up to avoid the
> allocation of an irq array.
> 
> This conversion adds VMState support.
> 
> It leaves the LOG_UIC() macro as-is to maximise the extent to which
> this is simply code-movement rather than a rewrite (in new code it
> would be better to use tracepoints).
> 
> The default property values for dcr-base and use-vectors are set to
> match those use by most of our boards with a UIC.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Applied to ppc-for-6.0, thanks.

> ---
>  include/hw/intc/ppc-uic.h |  73 +++++++++
>  hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
>  hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
>  MAINTAINERS               |   2 +
>  hw/intc/Kconfig           |   3 +
>  hw/intc/meson.build       |   1 +
>  hw/ppc/Kconfig            |   1 +
>  7 files changed, 431 insertions(+), 237 deletions(-)
>  create mode 100644 include/hw/intc/ppc-uic.h
>  create mode 100644 hw/intc/ppc-uic.c
> 
> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> new file mode 100644
> index 00000000000..e614e2ffd80
> --- /dev/null
> +++ b/include/hw/intc/ppc-uic.h
> @@ -0,0 +1,73 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_INTC_PPC_UIC_H
> +#define HW_INTC_PPC_UIC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_PPC_UIC "ppc-uic"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
> +
> +/*
> + * QEMU interface:
> + * QOM property "cpu": link to the PPC CPU
> + *    (no default, must be set)
> + * QOM property "dcr-base": base of the bank of DCR registers for the UIC
> + *    (default 0x30)
> + * QOM property "use-vectors": true if the UIC has vector registers
> + *    (default true)
> + * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
> + * sysbus IRQs:
> + *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
> + *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
> + */
> +
> +#define UIC_MAX_IRQ 32
> +
> +struct PPCUIC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +    qemu_irq output_cint;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    uint32_t dcr_base;
> +    bool use_vectors;
> +
> +    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> +    uint32_t uicsr;  /* Status register */
> +    uint32_t uicer;  /* Enable register */
> +    uint32_t uiccr;  /* Critical register */
> +    uint32_t uicpr;  /* Polarity register */
> +    uint32_t uictr;  /* Triggering register */
> +    uint32_t uicvcr; /* Vector configuration register */
> +    uint32_t uicvr;
> +};
> +
> +#endif
> diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
> new file mode 100644
> index 00000000000..b21951eea83
> --- /dev/null
> +++ b/hw/intc/ppc-uic.c
> @@ -0,0 +1,321 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "include/hw/intc/ppc-uic.h"
> +#include "hw/irq.h"
> +#include "cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +
> +enum {
> +    DCR_UICSR  = 0x000,
> +    DCR_UICSRS = 0x001,
> +    DCR_UICER  = 0x002,
> +    DCR_UICCR  = 0x003,
> +    DCR_UICPR  = 0x004,
> +    DCR_UICTR  = 0x005,
> +    DCR_UICMSR = 0x006,
> +    DCR_UICVR  = 0x007,
> +    DCR_UICVCR = 0x008,
> +    DCR_UICMAX = 0x009,
> +};
> +
> +/*#define DEBUG_UIC*/
> +
> +#ifdef DEBUG_UIC
> +#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
> +#else
> +#  define LOG_UIC(...) do { } while (0)
> +#endif
> +
> +static void ppcuic_trigger_irq(PPCUIC *uic)
> +{
> +    uint32_t ir, cr;
> +    int start, end, inc, i;
> +
> +    /* Trigger interrupt if any is pending */
> +    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> +    cr = uic->uicsr & uic->uicer & uic->uiccr;
> +    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> +                " uiccr %08" PRIx32 "\n"
> +                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> +                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> +                uic->uicsr & uic->uicer, ir, cr);
> +    if (ir != 0x0000000) {
> +        LOG_UIC("Raise UIC interrupt\n");
> +        qemu_irq_raise(uic->output_int);
> +    } else {
> +        LOG_UIC("Lower UIC interrupt\n");
> +        qemu_irq_lower(uic->output_int);
> +    }
> +    /* Trigger critical interrupt if any is pending and update vector */
> +    if (cr != 0x0000000) {
> +        qemu_irq_raise(uic->output_cint);
> +        if (uic->use_vectors) {
> +            /* Compute critical IRQ vector */
> +            if (uic->uicvcr & 1) {
> +                start = 31;
> +                end = 0;
> +                inc = -1;
> +            } else {
> +                start = 0;
> +                end = 31;
> +                inc = 1;
> +            }
> +            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> +            for (i = start; i <= end; i += inc) {
> +                if (cr & (1 << i)) {
> +                    uic->uicvr += (i - start) * 512 * inc;
> +                    break;
> +                }
> +            }
> +        }
> +        LOG_UIC("Raise UIC critical interrupt - "
> +                    "vector %08" PRIx32 "\n", uic->uicvr);
> +    } else {
> +        LOG_UIC("Lower UIC critical interrupt\n");
> +        qemu_irq_lower(uic->output_cint);
> +        uic->uicvr = 0x00000000;
> +    }
> +}
> +
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    PPCUIC *uic;
> +    uint32_t mask, sr;
> +
> +    uic = opaque;
> +    mask = 1U << (31 - irq_num);
> +    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> +                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> +                __func__, irq_num, level,
> +                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> +    if (irq_num < 0 || irq_num > 31) {
> +        return;
> +    }
> +    sr = uic->uicsr;
> +
> +    /* Update status register */
> +    if (uic->uictr & mask) {
> +        /* Edge sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +        }
> +    } else {
> +        /* Level sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +            uic->level |= mask;
> +        } else {
> +            uic->uicsr &= ~mask;
> +            uic->level &= ~mask;
> +        }
> +    }
> +    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> +                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> +    if (sr != uic->uicsr) {
> +        ppcuic_trigger_irq(uic);
> +    }
> +}
> +
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
> +{
> +    PPCUIC *uic;
> +    uint32_t ret;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +    case DCR_UICSRS:
> +        ret = uic->uicsr;
> +        break;
> +    case DCR_UICER:
> +        ret = uic->uicer;
> +        break;
> +    case DCR_UICCR:
> +        ret = uic->uiccr;
> +        break;
> +    case DCR_UICPR:
> +        ret = uic->uicpr;
> +        break;
> +    case DCR_UICTR:
> +        ret = uic->uictr;
> +        break;
> +    case DCR_UICMSR:
> +        ret = uic->uicsr & uic->uicer;
> +        break;
> +    case DCR_UICVR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvr;
> +        break;
> +    case DCR_UICVCR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvcr;
> +        break;
> +    default:
> +    no_read:
> +        ret = 0x00000000;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPCUIC *uic;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +        uic->uicsr &= ~val;
> +        uic->uicsr |= uic->level;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICSRS:
> +        uic->uicsr |= val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICER:
> +        uic->uicer = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICCR:
> +        uic->uiccr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICPR:
> +        uic->uicpr = val;
> +        break;
> +    case DCR_UICTR:
> +        uic->uictr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICMSR:
> +        break;
> +    case DCR_UICVR:
> +        break;
> +    case DCR_UICVCR:
> +        uic->uicvcr = val & 0xFFFFFFFD;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    }
> +}
> +
> +static void ppc_uic_reset(DeviceState *dev)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +
> +    uic->uiccr = 0x00000000;
> +    uic->uicer = 0x00000000;
> +    uic->uicpr = 0x00000000;
> +    uic->uicsr = 0x00000000;
> +    uic->uictr = 0x00000000;
> +    if (uic->use_vectors) {
> +        uic->uicvcr = 0x00000000;
> +        uic->uicvr = 0x0000000;
> +    }
> +}
> +
> +static void ppc_uic_realize(DeviceState *dev, Error **errp)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    PowerPCCPU *cpu;
> +    int i;
> +
> +    if (!uic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "ppc-uic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    cpu = POWERPC_CPU(uic->cpu);
> +    for (i = 0; i < DCR_UICMAX; i++) {
> +        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
> +                         &dcr_read_uic, &dcr_write_uic);
> +    }
> +
> +    sysbus_init_irq(sbd, &uic->output_int);
> +    sysbus_init_irq(sbd, &uic->output_cint);
> +    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
> +}
> +
> +static Property ppc_uic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
> +    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription ppc_uic_vmstate = {
> +    .name = "ppc-uic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, PPCUIC),
> +        VMSTATE_UINT32(uicsr, PPCUIC),
> +        VMSTATE_UINT32(uicer, PPCUIC),
> +        VMSTATE_UINT32(uiccr, PPCUIC),
> +        VMSTATE_UINT32(uicpr, PPCUIC),
> +        VMSTATE_UINT32(uictr, PPCUIC),
> +        VMSTATE_UINT32(uicvcr, PPCUIC),
> +        VMSTATE_UINT32(uicvr, PPCUIC),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void ppc_uic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ppc_uic_reset;
> +    dc->realize = ppc_uic_realize;
> +    dc->vmsd = &ppc_uic_vmstate;
> +    device_class_set_props(dc, ppc_uic_properties);
> +}
> +
> +static const TypeInfo ppc_uic_info = {
> +    .name = TYPE_PPC_UIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PPCUIC),
> +    .class_init = ppc_uic_class_init,
> +};
> +
> +static void ppc_uic_register_types(void)
> +{
> +    type_register_static(&ppc_uic_info);
> +}
> +
> +type_init(ppc_uic_register_types);
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f2f9ca4ffec..ffe4cf43e88 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -30,9 +30,12 @@
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/ppc4xx.h"
>  #include "hw/boards.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
>  #include "qemu/log.h"
>  #include "exec/address-spaces.h"
>  #include "qemu/error-report.h"
> +#include "qapi/error.h"
>  
>  /*#define DEBUG_UIC*/
>  
> @@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>  
>  /*****************************************************************************/
>  /* "Universal" Interrupt controller */
> -enum {
> -    DCR_UICSR  = 0x000,
> -    DCR_UICSRS = 0x001,
> -    DCR_UICER  = 0x002,
> -    DCR_UICCR  = 0x003,
> -    DCR_UICPR  = 0x004,
> -    DCR_UICTR  = 0x005,
> -    DCR_UICMSR = 0x006,
> -    DCR_UICVR  = 0x007,
> -    DCR_UICVCR = 0x008,
> -    DCR_UICMAX = 0x009,
> -};
> -
> -#define UIC_MAX_IRQ 32
> -typedef struct ppcuic_t ppcuic_t;
> -struct ppcuic_t {
> -    uint32_t dcr_base;
> -    int use_vectors;
> -    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> -    uint32_t uicsr;  /* Status register */
> -    uint32_t uicer;  /* Enable register */
> -    uint32_t uiccr;  /* Critical register */
> -    uint32_t uicpr;  /* Polarity register */
> -    uint32_t uictr;  /* Triggering register */
> -    uint32_t uicvcr; /* Vector configuration register */
> -    uint32_t uicvr;
> -    qemu_irq *irqs;
> -};
> -
> -static void ppcuic_trigger_irq(ppcuic_t *uic)
> -{
> -    uint32_t ir, cr;
> -    int start, end, inc, i;
> -
> -    /* Trigger interrupt if any is pending */
> -    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> -    cr = uic->uicsr & uic->uicer & uic->uiccr;
> -    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> -                " uiccr %08" PRIx32 "\n"
> -                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> -                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> -                uic->uicsr & uic->uicer, ir, cr);
> -    if (ir != 0x0000000) {
> -        LOG_UIC("Raise UIC interrupt\n");
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    } else {
> -        LOG_UIC("Lower UIC interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    }
> -    /* Trigger critical interrupt if any is pending and update vector */
> -    if (cr != 0x0000000) {
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        if (uic->use_vectors) {
> -            /* Compute critical IRQ vector */
> -            if (uic->uicvcr & 1) {
> -                start = 31;
> -                end = 0;
> -                inc = -1;
> -            } else {
> -                start = 0;
> -                end = 31;
> -                inc = 1;
> -            }
> -            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> -            for (i = start; i <= end; i += inc) {
> -                if (cr & (1 << i)) {
> -                    uic->uicvr += (i - start) * 512 * inc;
> -                    break;
> -                }
> -            }
> -        }
> -        LOG_UIC("Raise UIC critical interrupt - "
> -                    "vector %08" PRIx32 "\n", uic->uicvr);
> -    } else {
> -        LOG_UIC("Lower UIC critical interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        uic->uicvr = 0x00000000;
> -    }
> -}
> -
> -static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> -{
> -    ppcuic_t *uic;
> -    uint32_t mask, sr;
> -
> -    uic = opaque;
> -    mask = 1U << (31 - irq_num);
> -    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> -                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> -                __func__, irq_num, level,
> -                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31) {
> -        return;
> -    }
> -    sr = uic->uicsr;
> -
> -    /* Update status register */
> -    if (uic->uictr & mask) {
> -        /* Edge sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -        }
> -    } else {
> -        /* Level sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -            uic->level |= mask;
> -        } else {
> -            uic->uicsr &= ~mask;
> -            uic->level &= ~mask;
> -        }
> -    }
> -    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> -                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr) {
> -        ppcuic_trigger_irq(uic);
> -    }
> -}
> -
> -static uint32_t dcr_read_uic(void *opaque, int dcrn)
> -{
> -    ppcuic_t *uic;
> -    uint32_t ret;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -    case DCR_UICSRS:
> -        ret = uic->uicsr;
> -        break;
> -    case DCR_UICER:
> -        ret = uic->uicer;
> -        break;
> -    case DCR_UICCR:
> -        ret = uic->uiccr;
> -        break;
> -    case DCR_UICPR:
> -        ret = uic->uicpr;
> -        break;
> -    case DCR_UICTR:
> -        ret = uic->uictr;
> -        break;
> -    case DCR_UICMSR:
> -        ret = uic->uicsr & uic->uicer;
> -        break;
> -    case DCR_UICVR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvr;
> -        break;
> -    case DCR_UICVCR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvcr;
> -        break;
> -    default:
> -    no_read:
> -        ret = 0x00000000;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -        uic->uicsr &= ~val;
> -        uic->uicsr |= uic->level;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICSRS:
> -        uic->uicsr |= val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICER:
> -        uic->uicer = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICCR:
> -        uic->uiccr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICPR:
> -        uic->uicpr = val;
> -        break;
> -    case DCR_UICTR:
> -        uic->uictr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICMSR:
> -        break;
> -    case DCR_UICVR:
> -        break;
> -    case DCR_UICVCR:
> -        uic->uicvcr = val & 0xFFFFFFFD;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    }
> -}
> -
> -static void ppcuic_reset (void *opaque)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    uic->uiccr = 0x00000000;
> -    uic->uicer = 0x00000000;
> -    uic->uicpr = 0x00000000;
> -    uic->uicsr = 0x00000000;
> -    uic->uictr = 0x00000000;
> -    if (uic->use_vectors) {
> -        uic->uicvcr = 0x00000000;
> -        uic->uicvr = 0x0000000;
> -    }
> -}
>  
>  qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
>                         uint32_t dcr_base, int has_ssr, int has_vr)
>  {
> -    ppcuic_t *uic;
> +    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> +    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> +    qemu_irq *uic_irqs;
>      int i;
>  
> -    uic = g_malloc0(sizeof(ppcuic_t));
> -    uic->dcr_base = dcr_base;
> -    uic->irqs = irqs;
> -    if (has_vr)
> -        uic->use_vectors = 1;
> -    for (i = 0; i < DCR_UICMAX; i++) {
> -        ppc_dcr_register(env, dcr_base + i, uic,
> -                         &dcr_read_uic, &dcr_write_uic);
> -    }
> -    qemu_register_reset(ppcuic_reset, uic);
> +    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> +    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
>  
> -    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> +
> +    /*
> +     * Return an allocated array of the UIC's input IRQ lines.
> +     * This is an ugly temporary API to retain compatibility with
> +     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> +     * None of the callers free this array, so it is leaked -- but
> +     * so was the array allocated by qemu_allocate_irqs() in the
> +     * old code.
> +     *
> +     * The callers should just instantiate the UIC and wire it up
> +     * themselves rather than passing qemu_irq* in and out of this function.
> +     */
> +    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> +    for (i = 0; i < UIC_MAX_IRQ; i++) {
> +        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> +    }
> +    return uic_irqs;
>  }
>  
>  /*****************************************************************************/
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa39490a244..24218800b16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
>  F: hw/i2c/ppc4xx_i2c.c
>  F: include/hw/ppc/ppc4xx.h
>  F: include/hw/i2c/ppc4xx_i2c.h
> +F: hw/intc/ppc-uic.c
> +F: include/hw/intc/ppc-uic.h
>  
>  Character devices
>  M: Marc-André Lureau <marcandre.lureau@redhat.com>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index d07954086a5..468d548ca77 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,6 +62,9 @@ config S390_FLIC_KVM
>  config OMPIC
>      bool
>  
> +config PPC_UIC
> +    bool
> +
>  config RX_ICU
>      bool
>  
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 3f82cc230ad..d7dadbe5034 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
>  specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
>  specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
> +specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
>  specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
>  specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index dd86e664d21..982d55f5875 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -53,6 +53,7 @@ config PPC4XX
>      bool
>      select BITBANG_I2C
>      select PCI
> +    select PPC_UIC
>  
>  config SAM460EX
>      bool

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
  2020-12-13 14:32   ` Edgar E. Iglesias
@ 2020-12-14  5:55   ` David Gibson
  2021-01-11 19:04   ` BALATON Zoltan
  2 siblings, 0 replies; 39+ messages in thread
From: David Gibson @ 2020-12-14  5:55 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2565 bytes --]

On Sat, Dec 12, 2020 at 12:15:32AM +0000, Peter Maydell wrote:
> Switch the virtex_ml507 board to directly creating and
> configuring the UIC, rather than doing it via the old
> ppcuic_init() helper function.
> 
> This fixes a trivial Coverity-detected memory leak where
> we were leaking the array of IRQs returned by ppcuic_init().
> 
> Fixes: Coverity CID 1421992
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Applied to ppc-for-6.0.

> ---
>  hw/ppc/virtex_ml507.c | 21 ++++++++++++++++-----
>  1 file changed, 16 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
> index 7f1bca928c1..34767b11cad 100644
> --- a/hw/ppc/virtex_ml507.c
> +++ b/hw/ppc/virtex_ml507.c
> @@ -43,6 +43,7 @@
>  #include "qemu/option.h"
>  #include "exec/address-spaces.h"
>  
> +#include "hw/intc/ppc-uic.h"
>  #include "hw/ppc/ppc.h"
>  #include "hw/ppc/ppc4xx.h"
>  #include "hw/qdev-properties.h"
> @@ -95,7 +96,8 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
>  {
>      PowerPCCPU *cpu;
>      CPUPPCState *env;
> -    qemu_irq *irqs;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>  
>      cpu = POWERPC_CPU(cpu_create(cpu_type));
>      env = &cpu->env;
> @@ -105,10 +107,19 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
>      ppc_dcr_init(env, NULL, NULL);
>  
>      /* interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    ppcuic_init(env, irqs, 0x0C0, 0, 1);
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +
> +    /* This board doesn't wire anything up to the inputs of the UIC. */
>      return cpu;
>  }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 4/8] hw/ppc/ppc440_bamboo: " Peter Maydell
@ 2020-12-14  5:56   ` David Gibson
  2021-01-11  1:00   ` Nathan Chancellor
  1 sibling, 0 replies; 39+ messages in thread
From: David Gibson @ 2020-12-14  5:56 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4818 bytes --]

On Sat, Dec 12, 2020 at 12:15:33AM +0000, Peter Maydell wrote:
> Switch the bamboo board to directly creating and configuring the UIC,
> rather than doing it via the old ppcuic_init() helper function.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Applied to ppc-for-6.0.

> ---
>  hw/ppc/ppc440_bamboo.c | 38 +++++++++++++++++++++++++++-----------
>  1 file changed, 27 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
> index 665bc1784e1..b156bcb9990 100644
> --- a/hw/ppc/ppc440_bamboo.c
> +++ b/hw/ppc/ppc440_bamboo.c
> @@ -33,6 +33,9 @@
>  #include "sysemu/qtest.h"
>  #include "sysemu/reset.h"
>  #include "hw/sysbus.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
>  
>  #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
>  
> @@ -168,13 +171,13 @@ static void bamboo_init(MachineState *machine)
>      MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
>      hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
>      hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
> -    qemu_irq *pic;
> -    qemu_irq *irqs;
>      PCIBus *pcibus;
>      PowerPCCPU *cpu;
>      CPUPPCState *env;
>      target_long initrd_size = 0;
>      DeviceState *dev;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>      int success;
>      int i;
>  
> @@ -192,10 +195,17 @@ static void bamboo_init(MachineState *machine)
>      ppc_dcr_init(env, NULL, NULL);
>  
>      /* interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
>  
>      /* SDRAM controller */
>      memset(ram_bases, 0, sizeof(ram_bases));
> @@ -203,14 +213,18 @@ static void bamboo_init(MachineState *machine)
>      ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories,
>                         ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes);
>      /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
> -    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
> +    ppc4xx_sdram_init(env,
> +                      qdev_get_gpio_in(uicdev, 14),
> +                      PPC440EP_SDRAM_NR_BANKS, ram_memories,
>                        ram_bases, ram_sizes, 1);
>  
>      /* PCI */
>      dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
>                                  PPC440EP_PCI_CONFIG,
> -                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
> -                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
>                                  NULL);
>      pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>      if (!pcibus) {
> @@ -223,12 +237,14 @@ static void bamboo_init(MachineState *machine)
>      memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
>  
>      if (serial_hd(0) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
> +        serial_mm_init(address_space_mem, 0xef600300, 0,
> +                       qdev_get_gpio_in(uicdev, 0),
>                         PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
>                         DEVICE_BIG_ENDIAN);
>      }
>      if (serial_hd(1) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
> +        serial_mm_init(address_space_mem, 0xef600400, 0,
> +                       qdev_get_gpio_in(uicdev, 1),
>                         PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
>                         DEVICE_BIG_ENDIAN);
>      }

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/8] hw/ppc: Convert UIC device to QOM
  2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
                   ` (8 preceding siblings ...)
  2020-12-12 17:43 ` [PATCH 0/8] hw/ppc: Convert UIC device to QOM BALATON Zoltan via
@ 2020-12-14  6:00 ` David Gibson
  2020-12-14 10:04   ` Peter Maydell
  9 siblings, 1 reply; 39+ messages in thread
From: David Gibson @ 2020-12-14  6:00 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3507 bytes --]

On Sat, Dec 12, 2020 at 12:15:29AM +0000, Peter Maydell wrote:
> This patchseries converts the PPC UIC "Universal Interrupt
> Controller" to a QOM device.  My main reason for doing it is that
> this fixes a couple of long-standing trivial Coverity issues -- the
> current ppcuic_init() function allocates an array of qemu_irqs which
> the callers then leak.  (The leak is trivial because it happens once
> when QEMU starts.)
> 
> The patchseries converts the UIC to a QOM device but initially leaves
> the old ppcuic_init() creation function with its old API intact.  It
> then goes through converting the various boards that were using
> ppcuic_init() to instead directly create the UIC using the usual qdev
> APIs, so that it can delete the ppcuic_init() function entirely.
> 
> The patchset includes one patch which deletes 350 lines of dead code
> -- the ppc405cr_init() function seems to have never been used since
> it was added in 2007, so rather than converting this user of
> ppcuic_init() it seemed more sensible to delete it.
> 
> I have tested with 'make check' and 'make check-acceptance' but I
> don't think the latter really exercises the affected boards, which
> are:
> 
>  bamboo
>  ref405ep
>  sam460ex
>  taihu
>  virtex-ml507
> 
> I found instructions on how to boot an AROS image on sam460ex, so I
> have tested that: it works as well after this series as it did before
> (gets to "Libs/workbench.library" and stops); it does seem to
> successfully do things like scanning the USB bus and responding to
> keyboard input at the boot menu, which suggests that IRQs must be
> working.
> 
> Side note: the 'irq_inputs' hacks in the PPC CPU I think would really
> benefit from conversion to being qdev gpio inputs now that CPUs are
> real devices. There are also a lot of non-QOM devices in this
> ppc4xx code if anybody is interested in working on more QOM
> conversions for these boards.
> 
> thanks
> -- PMM

1..4 applied to my tree.  Looks like there are some comments needing
review on 5, so I'll leave the rest for another spin.

> 
> Peter Maydell (8):
>   hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
>   ppc: Convert PPC UIC to a QOM device
>   hw/ppc/virtex_ml507: Drop use of ppcuic_init()
>   hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
>   hw/ppc/sam460ex: Drop use of ppcuic_init()
>   hw/ppc: Delete unused ppc405cr_init() code
>   hw/ppc/ppc405_uc: Drop use of ppcuic_init()
>   hw/ppc: Remove unused ppcuic_init()
> 
>  hw/ppc/ppc405.h           |   8 +-
>  include/hw/intc/ppc-uic.h |  80 ++++++++
>  include/hw/ppc/ppc4xx.h   |   9 -
>  hw/intc/ppc-uic.c         | 321 +++++++++++++++++++++++++++++
>  hw/ppc/ppc405_boards.c    |   8 +-
>  hw/ppc/ppc405_uc.c        | 415 ++++----------------------------------
>  hw/ppc/ppc440_bamboo.c    |  38 +++-
>  hw/ppc/ppc4xx_devs.c      | 246 +---------------------
>  hw/ppc/sam460ex.c         |  70 +++++--
>  hw/ppc/virtex_ml507.c     |  21 +-
>  MAINTAINERS               |   2 +
>  hw/intc/Kconfig           |   3 +
>  hw/intc/meson.build       |   1 +
>  hw/ppc/Kconfig            |   1 +
>  14 files changed, 555 insertions(+), 668 deletions(-)
>  create mode 100644 include/hw/intc/ppc-uic.h
>  create mode 100644 hw/intc/ppc-uic.c
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/8] ppc: Convert PPC UIC to a QOM device
  2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
                     ` (3 preceding siblings ...)
  2020-12-14  5:54   ` David Gibson
@ 2020-12-14  9:12   ` BALATON Zoltan via
  4 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan via @ 2020-12-14  9:12 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

[-- Attachment #1: Type: text/plain, Size: 25247 bytes --]

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Currently the PPC UIC ("Universal Interrupt Controller") is implemented
> as a non-QOM device in ppc4xx_devs.c. Convert it to a proper QOM device
> in hw/intc.
>
> The ppcuic_init() function is retained for the moment with its current
> interface; in subsequent commits this will be tidied up to avoid the
> allocation of an irq array.
>
> This conversion adds VMState support.
>
> It leaves the LOG_UIC() macro as-is to maximise the extent to which
> this is simply code-movement rather than a rewrite (in new code it
> would be better to use tracepoints).
>
> The default property values for dcr-base and use-vectors are set to
> match those use by most of our boards with a UIC.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu>

David Gibson, My messages to you are bouncing with Host not found. Is it a 
problem with your mail server or just an overly agressive spam filter?

Regards,
BALATON Zoltan

> ---
> include/hw/intc/ppc-uic.h |  73 +++++++++
> hw/intc/ppc-uic.c         | 321 ++++++++++++++++++++++++++++++++++++++
> hw/ppc/ppc4xx_devs.c      | 267 ++++---------------------------
> MAINTAINERS               |   2 +
> hw/intc/Kconfig           |   3 +
> hw/intc/meson.build       |   1 +
> hw/ppc/Kconfig            |   1 +
> 7 files changed, 431 insertions(+), 237 deletions(-)
> create mode 100644 include/hw/intc/ppc-uic.h
> create mode 100644 hw/intc/ppc-uic.c
>
> diff --git a/include/hw/intc/ppc-uic.h b/include/hw/intc/ppc-uic.h
> new file mode 100644
> index 00000000000..e614e2ffd80
> --- /dev/null
> +++ b/include/hw/intc/ppc-uic.h
> @@ -0,0 +1,73 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef HW_INTC_PPC_UIC_H
> +#define HW_INTC_PPC_UIC_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_PPC_UIC "ppc-uic"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCUIC, PPC_UIC)
> +
> +/*
> + * QEMU interface:
> + * QOM property "cpu": link to the PPC CPU
> + *    (no default, must be set)
> + * QOM property "dcr-base": base of the bank of DCR registers for the UIC
> + *    (default 0x30)
> + * QOM property "use-vectors": true if the UIC has vector registers
> + *    (default true)
> + * unnamed GPIO inputs 0..UIC_MAX_IRQ: input IRQ lines
> + * sysbus IRQs:
> + *  0 (PPCUIC_OUTPUT_INT): output INT line to the CPU
> + *  1 (PPCUIC_OUTPUT_CINT): output CINT line to the CPU
> + */
> +
> +#define UIC_MAX_IRQ 32
> +
> +struct PPCUIC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +    qemu_irq output_cint;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    uint32_t dcr_base;
> +    bool use_vectors;
> +
> +    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> +    uint32_t uicsr;  /* Status register */
> +    uint32_t uicer;  /* Enable register */
> +    uint32_t uiccr;  /* Critical register */
> +    uint32_t uicpr;  /* Polarity register */
> +    uint32_t uictr;  /* Triggering register */
> +    uint32_t uicvcr; /* Vector configuration register */
> +    uint32_t uicvr;
> +};
> +
> +#endif
> diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
> new file mode 100644
> index 00000000000..b21951eea83
> --- /dev/null
> +++ b/hw/intc/ppc-uic.c
> @@ -0,0 +1,321 @@
> +/*
> + * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
> + *
> + * Copyright (c) 2007 Jocelyn Mayer
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "include/hw/intc/ppc-uic.h"
> +#include "hw/irq.h"
> +#include "cpu.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +
> +enum {
> +    DCR_UICSR  = 0x000,
> +    DCR_UICSRS = 0x001,
> +    DCR_UICER  = 0x002,
> +    DCR_UICCR  = 0x003,
> +    DCR_UICPR  = 0x004,
> +    DCR_UICTR  = 0x005,
> +    DCR_UICMSR = 0x006,
> +    DCR_UICVR  = 0x007,
> +    DCR_UICVCR = 0x008,
> +    DCR_UICMAX = 0x009,
> +};
> +
> +/*#define DEBUG_UIC*/
> +
> +#ifdef DEBUG_UIC
> +#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
> +#else
> +#  define LOG_UIC(...) do { } while (0)
> +#endif
> +
> +static void ppcuic_trigger_irq(PPCUIC *uic)
> +{
> +    uint32_t ir, cr;
> +    int start, end, inc, i;
> +
> +    /* Trigger interrupt if any is pending */
> +    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> +    cr = uic->uicsr & uic->uicer & uic->uiccr;
> +    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> +                " uiccr %08" PRIx32 "\n"
> +                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> +                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> +                uic->uicsr & uic->uicer, ir, cr);
> +    if (ir != 0x0000000) {
> +        LOG_UIC("Raise UIC interrupt\n");
> +        qemu_irq_raise(uic->output_int);
> +    } else {
> +        LOG_UIC("Lower UIC interrupt\n");
> +        qemu_irq_lower(uic->output_int);
> +    }
> +    /* Trigger critical interrupt if any is pending and update vector */
> +    if (cr != 0x0000000) {
> +        qemu_irq_raise(uic->output_cint);
> +        if (uic->use_vectors) {
> +            /* Compute critical IRQ vector */
> +            if (uic->uicvcr & 1) {
> +                start = 31;
> +                end = 0;
> +                inc = -1;
> +            } else {
> +                start = 0;
> +                end = 31;
> +                inc = 1;
> +            }
> +            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> +            for (i = start; i <= end; i += inc) {
> +                if (cr & (1 << i)) {
> +                    uic->uicvr += (i - start) * 512 * inc;
> +                    break;
> +                }
> +            }
> +        }
> +        LOG_UIC("Raise UIC critical interrupt - "
> +                    "vector %08" PRIx32 "\n", uic->uicvr);
> +    } else {
> +        LOG_UIC("Lower UIC critical interrupt\n");
> +        qemu_irq_lower(uic->output_cint);
> +        uic->uicvr = 0x00000000;
> +    }
> +}
> +
> +static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    PPCUIC *uic;
> +    uint32_t mask, sr;
> +
> +    uic = opaque;
> +    mask = 1U << (31 - irq_num);
> +    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> +                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> +                __func__, irq_num, level,
> +                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> +    if (irq_num < 0 || irq_num > 31) {
> +        return;
> +    }
> +    sr = uic->uicsr;
> +
> +    /* Update status register */
> +    if (uic->uictr & mask) {
> +        /* Edge sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +        }
> +    } else {
> +        /* Level sensitive interrupt */
> +        if (level == 1) {
> +            uic->uicsr |= mask;
> +            uic->level |= mask;
> +        } else {
> +            uic->uicsr &= ~mask;
> +            uic->level &= ~mask;
> +        }
> +    }
> +    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> +                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> +    if (sr != uic->uicsr) {
> +        ppcuic_trigger_irq(uic);
> +    }
> +}
> +
> +static uint32_t dcr_read_uic(void *opaque, int dcrn)
> +{
> +    PPCUIC *uic;
> +    uint32_t ret;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +    case DCR_UICSRS:
> +        ret = uic->uicsr;
> +        break;
> +    case DCR_UICER:
> +        ret = uic->uicer;
> +        break;
> +    case DCR_UICCR:
> +        ret = uic->uiccr;
> +        break;
> +    case DCR_UICPR:
> +        ret = uic->uicpr;
> +        break;
> +    case DCR_UICTR:
> +        ret = uic->uictr;
> +        break;
> +    case DCR_UICMSR:
> +        ret = uic->uicsr & uic->uicer;
> +        break;
> +    case DCR_UICVR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvr;
> +        break;
> +    case DCR_UICVCR:
> +        if (!uic->use_vectors) {
> +            goto no_read;
> +        }
> +        ret = uic->uicvcr;
> +        break;
> +    default:
> +    no_read:
> +        ret = 0x00000000;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPCUIC *uic;
> +
> +    uic = opaque;
> +    dcrn -= uic->dcr_base;
> +    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> +    switch (dcrn) {
> +    case DCR_UICSR:
> +        uic->uicsr &= ~val;
> +        uic->uicsr |= uic->level;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICSRS:
> +        uic->uicsr |= val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICER:
> +        uic->uicer = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICCR:
> +        uic->uiccr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICPR:
> +        uic->uicpr = val;
> +        break;
> +    case DCR_UICTR:
> +        uic->uictr = val;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    case DCR_UICMSR:
> +        break;
> +    case DCR_UICVR:
> +        break;
> +    case DCR_UICVCR:
> +        uic->uicvcr = val & 0xFFFFFFFD;
> +        ppcuic_trigger_irq(uic);
> +        break;
> +    }
> +}
> +
> +static void ppc_uic_reset(DeviceState *dev)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +
> +    uic->uiccr = 0x00000000;
> +    uic->uicer = 0x00000000;
> +    uic->uicpr = 0x00000000;
> +    uic->uicsr = 0x00000000;
> +    uic->uictr = 0x00000000;
> +    if (uic->use_vectors) {
> +        uic->uicvcr = 0x00000000;
> +        uic->uicvr = 0x0000000;
> +    }
> +}
> +
> +static void ppc_uic_realize(DeviceState *dev, Error **errp)
> +{
> +    PPCUIC *uic = PPC_UIC(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    PowerPCCPU *cpu;
> +    int i;
> +
> +    if (!uic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "ppc-uic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    cpu = POWERPC_CPU(uic->cpu);
> +    for (i = 0; i < DCR_UICMAX; i++) {
> +        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
> +                         &dcr_read_uic, &dcr_write_uic);
> +    }
> +
> +    sysbus_init_irq(sbd, &uic->output_int);
> +    sysbus_init_irq(sbd, &uic->output_cint);
> +    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
> +}
> +
> +static Property ppc_uic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0x30),
> +    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription ppc_uic_vmstate = {
> +    .name = "ppc-uic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(level, PPCUIC),
> +        VMSTATE_UINT32(uicsr, PPCUIC),
> +        VMSTATE_UINT32(uicer, PPCUIC),
> +        VMSTATE_UINT32(uiccr, PPCUIC),
> +        VMSTATE_UINT32(uicpr, PPCUIC),
> +        VMSTATE_UINT32(uictr, PPCUIC),
> +        VMSTATE_UINT32(uicvcr, PPCUIC),
> +        VMSTATE_UINT32(uicvr, PPCUIC),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void ppc_uic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = ppc_uic_reset;
> +    dc->realize = ppc_uic_realize;
> +    dc->vmsd = &ppc_uic_vmstate;
> +    device_class_set_props(dc, ppc_uic_properties);
> +}
> +
> +static const TypeInfo ppc_uic_info = {
> +    .name = TYPE_PPC_UIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(PPCUIC),
> +    .class_init = ppc_uic_class_init,
> +};
> +
> +static void ppc_uic_register_types(void)
> +{
> +    type_register_static(&ppc_uic_info);
> +}
> +
> +type_init(ppc_uic_register_types);
> diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
> index f2f9ca4ffec..ffe4cf43e88 100644
> --- a/hw/ppc/ppc4xx_devs.c
> +++ b/hw/ppc/ppc4xx_devs.c
> @@ -30,9 +30,12 @@
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/ppc4xx.h"
> #include "hw/boards.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> #include "qemu/log.h"
> #include "exec/address-spaces.h"
> #include "qemu/error-report.h"
> +#include "qapi/error.h"
>
> /*#define DEBUG_UIC*/
>
> @@ -76,250 +79,40 @@ PowerPCCPU *ppc4xx_init(const char *cpu_type,
>
> /*****************************************************************************/
> /* "Universal" Interrupt controller */
> -enum {
> -    DCR_UICSR  = 0x000,
> -    DCR_UICSRS = 0x001,
> -    DCR_UICER  = 0x002,
> -    DCR_UICCR  = 0x003,
> -    DCR_UICPR  = 0x004,
> -    DCR_UICTR  = 0x005,
> -    DCR_UICMSR = 0x006,
> -    DCR_UICVR  = 0x007,
> -    DCR_UICVCR = 0x008,
> -    DCR_UICMAX = 0x009,
> -};
> -
> -#define UIC_MAX_IRQ 32
> -typedef struct ppcuic_t ppcuic_t;
> -struct ppcuic_t {
> -    uint32_t dcr_base;
> -    int use_vectors;
> -    uint32_t level;  /* Remembers the state of level-triggered interrupts. */
> -    uint32_t uicsr;  /* Status register */
> -    uint32_t uicer;  /* Enable register */
> -    uint32_t uiccr;  /* Critical register */
> -    uint32_t uicpr;  /* Polarity register */
> -    uint32_t uictr;  /* Triggering register */
> -    uint32_t uicvcr; /* Vector configuration register */
> -    uint32_t uicvr;
> -    qemu_irq *irqs;
> -};
> -
> -static void ppcuic_trigger_irq(ppcuic_t *uic)
> -{
> -    uint32_t ir, cr;
> -    int start, end, inc, i;
> -
> -    /* Trigger interrupt if any is pending */
> -    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
> -    cr = uic->uicsr & uic->uicer & uic->uiccr;
> -    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
> -                " uiccr %08" PRIx32 "\n"
> -                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
> -                __func__, uic->uicsr, uic->uicer, uic->uiccr,
> -                uic->uicsr & uic->uicer, ir, cr);
> -    if (ir != 0x0000000) {
> -        LOG_UIC("Raise UIC interrupt\n");
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    } else {
> -        LOG_UIC("Lower UIC interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
> -    }
> -    /* Trigger critical interrupt if any is pending and update vector */
> -    if (cr != 0x0000000) {
> -        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        if (uic->use_vectors) {
> -            /* Compute critical IRQ vector */
> -            if (uic->uicvcr & 1) {
> -                start = 31;
> -                end = 0;
> -                inc = -1;
> -            } else {
> -                start = 0;
> -                end = 31;
> -                inc = 1;
> -            }
> -            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
> -            for (i = start; i <= end; i += inc) {
> -                if (cr & (1 << i)) {
> -                    uic->uicvr += (i - start) * 512 * inc;
> -                    break;
> -                }
> -            }
> -        }
> -        LOG_UIC("Raise UIC critical interrupt - "
> -                    "vector %08" PRIx32 "\n", uic->uicvr);
> -    } else {
> -        LOG_UIC("Lower UIC critical interrupt\n");
> -        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
> -        uic->uicvr = 0x00000000;
> -    }
> -}
> -
> -static void ppcuic_set_irq(void *opaque, int irq_num, int level)
> -{
> -    ppcuic_t *uic;
> -    uint32_t mask, sr;
> -
> -    uic = opaque;
> -    mask = 1U << (31 - irq_num);
> -    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
> -                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
> -                __func__, irq_num, level,
> -                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
> -    if (irq_num < 0 || irq_num > 31) {
> -        return;
> -    }
> -    sr = uic->uicsr;
> -
> -    /* Update status register */
> -    if (uic->uictr & mask) {
> -        /* Edge sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -        }
> -    } else {
> -        /* Level sensitive interrupt */
> -        if (level == 1) {
> -            uic->uicsr |= mask;
> -            uic->level |= mask;
> -        } else {
> -            uic->uicsr &= ~mask;
> -            uic->level &= ~mask;
> -        }
> -    }
> -    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
> -                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
> -    if (sr != uic->uicsr) {
> -        ppcuic_trigger_irq(uic);
> -    }
> -}
> -
> -static uint32_t dcr_read_uic(void *opaque, int dcrn)
> -{
> -    ppcuic_t *uic;
> -    uint32_t ret;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -    case DCR_UICSRS:
> -        ret = uic->uicsr;
> -        break;
> -    case DCR_UICER:
> -        ret = uic->uicer;
> -        break;
> -    case DCR_UICCR:
> -        ret = uic->uiccr;
> -        break;
> -    case DCR_UICPR:
> -        ret = uic->uicpr;
> -        break;
> -    case DCR_UICTR:
> -        ret = uic->uictr;
> -        break;
> -    case DCR_UICMSR:
> -        ret = uic->uicsr & uic->uicer;
> -        break;
> -    case DCR_UICVR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvr;
> -        break;
> -    case DCR_UICVCR:
> -        if (!uic->use_vectors) {
> -            goto no_read;
> -        }
> -        ret = uic->uicvcr;
> -        break;
> -    default:
> -    no_read:
> -        ret = 0x00000000;
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
> -static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    dcrn -= uic->dcr_base;
> -    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
> -    switch (dcrn) {
> -    case DCR_UICSR:
> -        uic->uicsr &= ~val;
> -        uic->uicsr |= uic->level;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICSRS:
> -        uic->uicsr |= val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICER:
> -        uic->uicer = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICCR:
> -        uic->uiccr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICPR:
> -        uic->uicpr = val;
> -        break;
> -    case DCR_UICTR:
> -        uic->uictr = val;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    case DCR_UICMSR:
> -        break;
> -    case DCR_UICVR:
> -        break;
> -    case DCR_UICVCR:
> -        uic->uicvcr = val & 0xFFFFFFFD;
> -        ppcuic_trigger_irq(uic);
> -        break;
> -    }
> -}
> -
> -static void ppcuic_reset (void *opaque)
> -{
> -    ppcuic_t *uic;
> -
> -    uic = opaque;
> -    uic->uiccr = 0x00000000;
> -    uic->uicer = 0x00000000;
> -    uic->uicpr = 0x00000000;
> -    uic->uicsr = 0x00000000;
> -    uic->uictr = 0x00000000;
> -    if (uic->use_vectors) {
> -        uic->uicvcr = 0x00000000;
> -        uic->uicvr = 0x0000000;
> -    }
> -}
>
> qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
>                        uint32_t dcr_base, int has_ssr, int has_vr)
> {
> -    ppcuic_t *uic;
> +    DeviceState *uicdev = qdev_new(TYPE_PPC_UIC);
> +    SysBusDevice *uicsbd = SYS_BUS_DEVICE(uicdev);
> +    qemu_irq *uic_irqs;
>     int i;
>
> -    uic = g_malloc0(sizeof(ppcuic_t));
> -    uic->dcr_base = dcr_base;
> -    uic->irqs = irqs;
> -    if (has_vr)
> -        uic->use_vectors = 1;
> -    for (i = 0; i < DCR_UICMAX; i++) {
> -        ppc_dcr_register(env, dcr_base + i, uic,
> -                         &dcr_read_uic, &dcr_write_uic);
> -    }
> -    qemu_register_reset(ppcuic_reset, uic);
> +    qdev_prop_set_uint32(uicdev, "dcr-base", dcr_base);
> +    qdev_prop_set_bit(uicdev, "use-vectors", has_vr);
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(env_cpu(env)),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
>
> -    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT, irqs[PPCUIC_OUTPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT, irqs[PPCUIC_OUTPUT_CINT]);
> +
> +    /*
> +     * Return an allocated array of the UIC's input IRQ lines.
> +     * This is an ugly temporary API to retain compatibility with
> +     * the ppcuic_init() interface from the pre-QOM-conversion UIC.
> +     * None of the callers free this array, so it is leaked -- but
> +     * so was the array allocated by qemu_allocate_irqs() in the
> +     * old code.
> +     *
> +     * The callers should just instantiate the UIC and wire it up
> +     * themselves rather than passing qemu_irq* in and out of this function.
> +     */
> +    uic_irqs = g_new0(qemu_irq, UIC_MAX_IRQ);
> +    for (i = 0; i < UIC_MAX_IRQ; i++) {
> +        uic_irqs[i] = qdev_get_gpio_in(uicdev, i);
> +    }
> +    return uic_irqs;
> }
>
> /*****************************************************************************/
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa39490a244..24218800b16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1671,6 +1671,8 @@ F: hw/ppc/ppc4*.c
> F: hw/i2c/ppc4xx_i2c.c
> F: include/hw/ppc/ppc4xx.h
> F: include/hw/i2c/ppc4xx_i2c.h
> +F: hw/intc/ppc-uic.c
> +F: include/hw/intc/ppc-uic.h
>
> Character devices
> M: Marc-André Lureau <marcandre.lureau@redhat.com>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index d07954086a5..468d548ca77 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,6 +62,9 @@ config S390_FLIC_KVM
> config OMPIC
>     bool
>
> +config PPC_UIC
> +    bool
> +
> config RX_ICU
>     bool
>
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 3f82cc230ad..d7dadbe5034 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -42,6 +42,7 @@ specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_intc.c'))
> specific_ss.add(when: 'CONFIG_OMPIC', if_true: files('ompic.c'))
> specific_ss.add(when: 'CONFIG_OPENPIC_KVM', if_true: files('openpic_kvm.c'))
> specific_ss.add(when: 'CONFIG_POWERNV', if_true: files('xics_pnv.c', 'pnv_xive.c'))
> +specific_ss.add(when: 'CONFIG_PPC_UIC', if_true: files('ppc-uic.c'))
> specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_control.c'))
> specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index dd86e664d21..982d55f5875 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -53,6 +53,7 @@ config PPC4XX
>     bool
>     select BITBANG_I2C
>     select PCI
> +    select PPC_UIC
>
> config SAM460EX
>     bool
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code
  2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
                     ` (2 preceding siblings ...)
  2020-12-14  5:43   ` David Gibson
@ 2020-12-14  9:15   ` Thomas Huth
  3 siblings, 0 replies; 39+ messages in thread
From: Thomas Huth @ 2020-12-14  9:15 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel; +Cc: Edgar E. Iglesias, qemu-ppc, David Gibson

On 12/12/2020 01.15, Peter Maydell wrote:
> In a following commit we will move the PPC UIC implementation to
> its own file in hw/intc. To prevent checkpatch complaining about that
> code-motion, fix up the minor style issues first.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/ppc/ppc4xx_devs.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)

Reviewed-by: Thomas Huth <thuth@redhat.com>



^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/8] hw/ppc: Convert UIC device to QOM
  2020-12-14  6:00 ` David Gibson
@ 2020-12-14 10:04   ` Peter Maydell
  0 siblings, 0 replies; 39+ messages in thread
From: Peter Maydell @ 2020-12-14 10:04 UTC (permalink / raw)
  To: David Gibson; +Cc: Edgar E. Iglesias, qemu-ppc, QEMU Developers

On Mon, 14 Dec 2020 at 09:01, David Gibson <david@gibson.dropbear.id.au> wrote:
>
> On Sat, Dec 12, 2020 at 12:15:29AM +0000, Peter Maydell wrote:
> > This patchseries converts the PPC UIC "Universal Interrupt
> > Controller" to a QOM device.  My main reason for doing it is that
> > this fixes a couple of long-standing trivial Coverity issues -- the
> > current ppcuic_init() function allocates an array of qemu_irqs which
> > the callers then leak.  (The leak is trivial because it happens once
> > when QEMU starts.)
> 1..4 applied to my tree.  Looks like there are some comments needing
> review on 5, so I'll leave the rest for another spin.

Thanks. You could take 6 as well if you like (it's the "delete dead
code" one). I'll try to get a respin out this week, but otherwise
it can wait for January.

-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 4/8] hw/ppc/ppc440_bamboo: " Peter Maydell
  2020-12-14  5:56   ` David Gibson
@ 2021-01-11  1:00   ` Nathan Chancellor
  2021-01-11 17:14     ` Peter Maydell
  2021-02-03 16:35     ` Philippe Mathieu-Daudé
  1 sibling, 2 replies; 39+ messages in thread
From: Nathan Chancellor @ 2021-01-11  1:00 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Edgar E. Iglesias, qemu-ppc, qemu-devel, David Gibson

On Sat, Dec 12, 2020 at 12:15:33AM +0000, Peter Maydell wrote:
> Switch the bamboo board to directly creating and configuring the UIC,
> rather than doing it via the old ppcuic_init() helper function.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/ppc/ppc440_bamboo.c | 38 +++++++++++++++++++++++++++-----------
>  1 file changed, 27 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
> index 665bc1784e1..b156bcb9990 100644
> --- a/hw/ppc/ppc440_bamboo.c
> +++ b/hw/ppc/ppc440_bamboo.c
> @@ -33,6 +33,9 @@
>  #include "sysemu/qtest.h"
>  #include "sysemu/reset.h"
>  #include "hw/sysbus.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
>  
>  #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
>  
> @@ -168,13 +171,13 @@ static void bamboo_init(MachineState *machine)
>      MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
>      hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
>      hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
> -    qemu_irq *pic;
> -    qemu_irq *irqs;
>      PCIBus *pcibus;
>      PowerPCCPU *cpu;
>      CPUPPCState *env;
>      target_long initrd_size = 0;
>      DeviceState *dev;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>      int success;
>      int i;
>  
> @@ -192,10 +195,17 @@ static void bamboo_init(MachineState *machine)
>      ppc_dcr_init(env, NULL, NULL);
>  
>      /* interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);
> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
>  
>      /* SDRAM controller */
>      memset(ram_bases, 0, sizeof(ram_bases));
> @@ -203,14 +213,18 @@ static void bamboo_init(MachineState *machine)
>      ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories,
>                         ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes);
>      /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
> -    ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
> +    ppc4xx_sdram_init(env,
> +                      qdev_get_gpio_in(uicdev, 14),
> +                      PPC440EP_SDRAM_NR_BANKS, ram_memories,
>                        ram_bases, ram_sizes, 1);
>  
>      /* PCI */
>      dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
>                                  PPC440EP_PCI_CONFIG,
> -                                pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
> -                                pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
> +                                qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
>                                  NULL);
>      pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
>      if (!pcibus) {
> @@ -223,12 +237,14 @@ static void bamboo_init(MachineState *machine)
>      memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
>  
>      if (serial_hd(0) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
> +        serial_mm_init(address_space_mem, 0xef600300, 0,
> +                       qdev_get_gpio_in(uicdev, 0),
>                         PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
>                         DEVICE_BIG_ENDIAN);
>      }
>      if (serial_hd(1) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
> +        serial_mm_init(address_space_mem, 0xef600400, 0,
> +                       qdev_get_gpio_in(uicdev, 1),
>                         PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
>                         DEVICE_BIG_ENDIAN);
>      }
> -- 
> 2.20.1
> 
> 

Hopefully reporting this here is okay, I find Launchpad hard to use but
I can file it there if need be.

This patch causes a panic while trying to boot a ppc44x_defconfig Linux
kernel:

$ qemu-system-ppc \
    -machine bamboo \
    -no-reboot \
    -append console=ttyS0 \
    -display none \
    -kernel uImage \
    -m 128m \
    -nodefaults \
    -serial mon:stdio
Linux version 5.11.0-rc3 (nathan@ubuntu-m3-large-x86) (powerpc-linux-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35) #1 Sun Jan 10 15:52:24 MST 2021
Using PowerPC 44x Platform machine description
ioremap() called early from find_legacy_serial_ports+0x64c/0x794. Use early_ioremap() instead
printk: bootconsole [udbg0] enabled
-----------------------------------------------------
phys_mem_size     = 0x8000000
dcache_bsize      = 0x20
icache_bsize      = 0x20
cpu_features      = 0x0000000000000100
  possible        = 0x0000000040000100
  always          = 0x0000000000000100
cpu_user_features = 0x8c008000 0x00000000
mmu_features      = 0x00000008
-----------------------------------------------------
Zone ranges:
  Normal   [mem 0x0000000000000000-0x0000000007ffffff]
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000000000000-0x0000000007ffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x0000000007ffffff]
MMU: Allocated 1088 bytes of context maps for 255 contexts
Built 1 zonelists, mobility grouping on.  Total pages: 32448
Kernel command line: console=ttyS0
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes, linear)
mem auto-init: stack:off, heap alloc:off, heap free:off
Memory: 122712K/131072K available (5040K kernel code, 236K rwdata, 1260K rodata, 200K init, 134K bss, 8360K reserved, 0K cma-reserved)
Kernel virtual memory layout:
  * 0xffbdf000..0xfffff000  : fixmap
  * 0xffbdd000..0xffbdf000  : early ioremap
  * 0xd1000000..0xffbdd000  : vmalloc & ioremap
SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS: 512, nr_irqs: 512, preallocated irqs: 16
Oops: Exception in kernel mode, sig: 4 [#1]
BE PAGE_SIZE=4K PowerPC 44x Platform
Modules linked in:
CPU: 0 PID: 0 Comm: swapper Not tainted 5.11.0-rc3 #1
NIP:  c0019e58 LR: c062e3a0 CTR: c0019e58
REGS: c067fe90 TRAP: 0700   Not tainted  (5.11.0-rc3)
MSR:  000a1000 <CE,ME>  CR: 84000224  XER: 20000000

GPR00: c062e370 c067ff50 c065c300 c0019e58 00000000 c0019238 c067fde0 c065c300
GPR08: 00000000 00000000 c066fca4 00000066 84000222 00000000 00000000 00000000
GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 c0000010 00000000
GPR24: c0651594 c0651594 c0690000 c7ffe080 c0690000 c05c6f64 c0680000 c0802100
NIP [c0019e58] __mtdcr_table+0xc20/0x3ff8
LR [c062e3a0] uic_init_one+0x13c/0x214
Call Trace:
[c067ff50] [c062e370] uic_init_one+0x10c/0x214 (unreliable)
[c067ff80] [c062e4f8] uic_init_tree+0x80/0x174
[c067ffb0] [c0627af8] start_kernel+0x33c/0x508
[c067fff0] [c0000044] _start+0x44/0x88
Instruction dump:
7c9f2b86 4e800020 7c603286 4e800020 7c803386 4e800020 7c613286 4e800020
7c813386 4e800020 7c623286 4e800020 <7c823386> 4e800020 7c633286 4e800020
random: get_random_bytes called from oops_exit+0x44/0x84 with crng_init=0
---[ end trace 0000000000000000 ]---

Kernel panic - not syncing: Attempted to kill the idle task!
Rebooting in 180 seconds..

I have uploaded the kernel image here:

https://github.com/nathanchance/bug-files/blob/8edf230441bd8eda067973fdf0eb063c94f04379/qemu-0270d74ef886235051c13c39b0de88500c628a02/uImage

Do note that this is not the only commit that causes an issue on this
machine, there is also a few assertion failures which I am about to
report as well.

Cheers,
Nathan


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2021-01-11  1:00   ` Nathan Chancellor
@ 2021-01-11 17:14     ` Peter Maydell
  2021-01-11 18:22       ` Mark Cave-Ayland
  2021-02-03 16:35     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 39+ messages in thread
From: Peter Maydell @ 2021-01-11 17:14 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Edgar E. Iglesias, qemu-ppc, QEMU Developers, David Gibson

On Mon, 11 Jan 2021 at 01:00, Nathan Chancellor
<natechancellor@gmail.com> wrote:
>
> On Sat, Dec 12, 2020 at 12:15:33AM +0000, Peter Maydell wrote:
> > Switch the bamboo board to directly creating and configuring the UIC,
> > rather than doing it via the old ppcuic_init() helper function.

> Hopefully reporting this here is okay, I find Launchpad hard to use but
> I can file it there if need be.

Email reports are fine, thanks.

> This patch causes a panic while trying to boot a ppc44x_defconfig Linux
> kernel:

Sorry, yes, this is a bug in this commit of mine. I didn't notice
in the conversion that Bamboo has a non-standard DCR base register
value. I'll just send a patch for this in a second.

Thanks for the repro case.

NB: with the fix for the the kernel proceeds on to the PCI
related assert that it hit in 5.2.

-- PMM


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2021-01-11 17:14     ` Peter Maydell
@ 2021-01-11 18:22       ` Mark Cave-Ayland
  0 siblings, 0 replies; 39+ messages in thread
From: Mark Cave-Ayland @ 2021-01-11 18:22 UTC (permalink / raw)
  To: Peter Maydell, Nathan Chancellor
  Cc: Edgar E. Iglesias, qemu-ppc, QEMU Developers, David Gibson

On 11/01/2021 17:14, Peter Maydell wrote:

>> On Sat, Dec 12, 2020 at 12:15:33AM +0000, Peter Maydell wrote:
>>> Switch the bamboo board to directly creating and configuring the UIC,
>>> rather than doing it via the old ppcuic_init() helper function.
> 
>> Hopefully reporting this here is okay, I find Launchpad hard to use but
>> I can file it there if need be.
> 
> Email reports are fine, thanks.
> 
>> This patch causes a panic while trying to boot a ppc44x_defconfig Linux
>> kernel:
> 
> Sorry, yes, this is a bug in this commit of mine. I didn't notice
> in the conversion that Bamboo has a non-standard DCR base register
> value. I'll just send a patch for this in a second.
> 
> Thanks for the repro case.
> 
> NB: with the fix for the the kernel proceeds on to the PCI
> related assert that it hit in 5.2.

FWIW the assert() seems to be the same problem that Guenter reported at 
https://lists.gnu.org/archive/html/qemu-devel/2020-12/msg05847.html.

According to Linux's bamboo.dts the PCI slots look this:

     /* Bamboo has all 4 IRQ pins tied together per slot */
     interrupt-map-mask = <0xf800 0x0 0x0 0x0>;
     interrupt-map = <
         /* IDSEL 1 */
         0x800 0x0 0x0 0x0 &UIC0 0x1c 0x8

         /* IDSEL 2 */
         0x1000 0x0 0x0 0x0 &UIC0 0x1b 0x8

         /* IDSEL 3 */
         0x1800 0x0 0x0 0x0 &UIC0 0x1a 0x8

         /* IDSEL 4 */
         0x2000 0x0 0x0 0x0 &UIC0 0x19 0x8
     >;

But the assert() is suggesting that we are getting an PCI IRQ of -1 which can only 
come from slot 0 which isn't physically possible:

/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
  * may need further refactoring for other boards. */
static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
{
     int slot = PCI_SLOT(pci_dev->devfn);

     trace_ppc4xx_pci_map_irq(pci_dev->devfn, irq_num, slot);

     return slot - 1;
}

And indeed the backtrace shows that the PCI host bridge itself is generating this IRQ:

(gdb) bt
#0  ppc4xx_pci_map_irq (pci_dev=0x555556c0efe0, irq_num=0) at ../hw/ppc/ppc4xx_pci.c:250
#1  0x00005555559420d9 in pci_change_irq_level (pci_dev=0x555556c0efe0, irq_num=0, 
change=0) at ../hw/pci/pci.c:266
#2  0x0000555555944d56 in pci_update_irq_disabled (d=0x555556c0efe0, 
was_irq_disabled=0) at ../hw/pci/pci.c:1386
#3  0x0000555555945086 in pci_default_write_config (d=0x555556c0efe0, addr=4, 
val_in=1030, l=2) at ../hw/pci/pci.c:1426
#4  0x0000555555aa5b7e in pci_host_config_write_common (pci_dev=0x555556c0efe0, 
addr=4, limit=256, val=1030, len=2) at ../hw/pci/pci_host.c:83
#5  0x0000555555aa5ce2 in pci_data_write (s=0x555556c0e400, addr=2147483652, 
val=1030, len=2) at ../hw/pci/pci_host.c:120
#6  0x0000555555aa5e08 in pci_host_data_write (opaque=0x555556c0ce70, addr=0, 
val=1030, len=2) at ../hw/pci/pci_host.c:167
#7  0x0000555555cb4797 in memory_region_write_accessor (mr=0x555556c0d280, addr=0, 
value=0x7fffe60234a8, size=2, shift=0, mask=65535, attrs=...)
     at ../softmmu/memory.c:491

The assert() is correct since it correctly identifies an underflow of the PCI IRQ 
array but what is the best solution? I guess the possibilities are to either i) map 
the PCI host bridge IRQ to PCI IRQ 0 so at least it doesn't fail or ii) add an extra 
PCI IRQ 0 for the PCI host bridge and leave it unconnected.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
  2020-12-13 14:32   ` Edgar E. Iglesias
  2020-12-14  5:55   ` David Gibson
@ 2021-01-11 19:04   ` BALATON Zoltan
  2 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan @ 2021-01-11 19:04 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Switch the virtex_ml507 board to directly creating and
> configuring the UIC, rather than doing it via the old
> ppcuic_init() helper function.
>
> This fixes a trivial Coverity-detected memory leak where
> we were leaking the array of IRQs returned by ppcuic_init().
>
> Fixes: Coverity CID 1421992
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/ppc/virtex_ml507.c | 21 ++++++++++++++++-----
> 1 file changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
> index 7f1bca928c1..34767b11cad 100644
> --- a/hw/ppc/virtex_ml507.c
> +++ b/hw/ppc/virtex_ml507.c
> @@ -43,6 +43,7 @@
> #include "qemu/option.h"
> #include "exec/address-spaces.h"
>
> +#include "hw/intc/ppc-uic.h"
> #include "hw/ppc/ppc.h"
> #include "hw/ppc/ppc4xx.h"
> #include "hw/qdev-properties.h"
> @@ -95,7 +96,8 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
> {
>     PowerPCCPU *cpu;
>     CPUPPCState *env;
> -    qemu_irq *irqs;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>
>     cpu = POWERPC_CPU(cpu_create(cpu_type));
>     env = &cpu->env;
> @@ -105,10 +107,19 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
>     ppc_dcr_init(env, NULL, NULL);
>
>     /* interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    ppcuic_init(env, irqs, 0x0C0, 0, 1);
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);

This also uses 0xc0 which is not set. I don't know where's your default 
value comes from but I all these boards seem to use 0xc0 rather than that 
default. So maybe this is better fixed in the UIC dev to change the 
default to 0xc0?

Regards,
BALATON Zoltan

> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +
> +    /* This board doesn't wire anything up to the inputs of the UIC. */
>     return cpu;
> }
>
> -- 
> 2.20.1
>
>
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init()
  2020-12-12  0:15 ` [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init() Peter Maydell
@ 2021-01-11 19:09   ` BALATON Zoltan
  0 siblings, 0 replies; 39+ messages in thread
From: BALATON Zoltan @ 2021-01-11 19:09 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-ppc, qemu-devel, David Gibson

On Sat, 12 Dec 2020, Peter Maydell wrote:
> Switch the ppc405_uc boards to directly creating and configuring the
> UIC, rather than doing it via the old ppcuic_init() helper function.
>
> We retain the API feature of ppc405ep_init() where it passes back
> something allowing the callers to wire up devices to the UIC if
> they need to, even though neither of the callsites currently makes
> use of this ability -- instead of passing back the qemu_irq array
> we pass back the UIC DeviceState.
>
> This fixes a trivial Coverity-detected memory leak where
> we were leaking the array of IRQs returned by ppcuic_init().
>
> Fixes: Coverity CID 1421922
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/ppc/ppc405.h        |  2 +-
> hw/ppc/ppc405_boards.c |  8 ++---
> hw/ppc/ppc405_uc.c     | 70 +++++++++++++++++++++++++-----------------
> 3 files changed, 47 insertions(+), 33 deletions(-)
>
> diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h
> index e6c702f7e0d..c58f739886a 100644
> --- a/hw/ppc/ppc405.h
> +++ b/hw/ppc/ppc405.h
> @@ -66,7 +66,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
>                         MemoryRegion ram_memories[2],
>                         hwaddr ram_bases[2],
>                         hwaddr ram_sizes[2],
> -                        uint32_t sysclk, qemu_irq **picp,
> +                        uint32_t sysclk, DeviceState **uicdev,
>                         int do_init);
>
> #endif /* PPC405_H */
> diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
> index b7249f21cf2..8f77887fb18 100644
> --- a/hw/ppc/ppc405_boards.c
> +++ b/hw/ppc/ppc405_boards.c
> @@ -151,7 +151,6 @@ static void ref405ep_init(MachineState *machine)
>     CPUPPCState *env;
>     DeviceState *dev;
>     SysBusDevice *s;
> -    qemu_irq *pic;
>     MemoryRegion *bios;
>     MemoryRegion *sram = g_new(MemoryRegion, 1);
>     ram_addr_t bdloc;
> @@ -167,6 +166,7 @@ static void ref405ep_init(MachineState *machine)
>     int len;
>     DriveInfo *dinfo;
>     MemoryRegion *sysmem = get_system_memory();
> +    DeviceState *uicdev;
>
>     if (machine->ram_size != mc->default_ram_size) {
>         char *sz = size_to_str(mc->default_ram_size);
> @@ -184,7 +184,7 @@ static void ref405ep_init(MachineState *machine)
>     ram_bases[1] = 0x00000000;
>     ram_sizes[1] = 0x00000000;
>     env = ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
> -                        33333333, &pic, kernel_filename == NULL ? 0 : 1);
> +                        33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
>     /* allocate SRAM */
>     sram_size = 512 * KiB;
>     memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size,
> @@ -429,7 +429,6 @@ static void taihu_405ep_init(MachineState *machine)
>     const char *kernel_filename = machine->kernel_filename;
>     const char *initrd_filename = machine->initrd_filename;
>     char *filename;
> -    qemu_irq *pic;
>     MemoryRegion *sysmem = get_system_memory();
>     MemoryRegion *bios;
>     MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
> @@ -440,6 +439,7 @@ static void taihu_405ep_init(MachineState *machine)
>     int linux_boot;
>     int fl_idx;
>     DriveInfo *dinfo;
> +    DeviceState *uicdev;
>
>     if (machine->ram_size != mc->default_ram_size) {
>         char *sz = size_to_str(mc->default_ram_size);
> @@ -459,7 +459,7 @@ static void taihu_405ep_init(MachineState *machine)
>                              "taihu_405ep.ram-1", machine->ram, ram_bases[1],
>                              ram_sizes[1]);
>     ppc405ep_init(sysmem, ram_memories, ram_bases, ram_sizes,
> -                  33333333, &pic, kernel_filename == NULL ? 0 : 1);
> +                  33333333, &uicdev, kernel_filename == NULL ? 0 : 1);
>     /* allocate and load BIOS */
>     fl_idx = 0;
> #if defined(USE_FLASH_BIOS)
> diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
> index 3e191ae4af5..fe047074a17 100644
> --- a/hw/ppc/ppc405_uc.c
> +++ b/hw/ppc/ppc405_uc.c
> @@ -36,6 +36,9 @@
> #include "sysemu/sysemu.h"
> #include "qemu/log.h"
> #include "exec/address-spaces.h"
> +#include "hw/intc/ppc-uic.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
>
> //#define DEBUG_OPBA
> //#define DEBUG_SDRAM
> @@ -1446,14 +1449,15 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
>                         MemoryRegion ram_memories[2],
>                         hwaddr ram_bases[2],
>                         hwaddr ram_sizes[2],
> -                        uint32_t sysclk, qemu_irq **picp,
> +                        uint32_t sysclk, DeviceState **uicdevp,
>                         int do_init)
> {
>     clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
>     qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
>     PowerPCCPU *cpu;
>     CPUPPCState *env;
> -    qemu_irq *pic, *irqs;
> +    DeviceState *uicdev;
> +    SysBusDevice *uicsbd;
>
>     memset(clk_setup, 0, sizeof(clk_setup));
>     /* init CPUs */
> @@ -1474,59 +1478,69 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
>     /* Initialize timers */
>     ppc_booke_timers_init(cpu, sysclk, 0);
>     /* Universal interrupt controller */
> -    irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
> -    irqs[PPCUIC_OUTPUT_INT] =
> -        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> -    irqs[PPCUIC_OUTPUT_CINT] =
> -        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> -    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
> -    *picp = pic;
> +    uicdev = qdev_new(TYPE_PPC_UIC);
> +    uicsbd = SYS_BUS_DEVICE(uicdev);
> +
> +    object_property_set_link(OBJECT(uicdev), "cpu", OBJECT(cpu),
> +                             &error_fatal);
> +    sysbus_realize_and_unref(uicsbd, &error_fatal);

Here too it's 0xc0.

Regards,
BALATON Zoltan

> +
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
> +    sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
> +                       ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
> +
> +    *uicdevp = uicdev;
> +
>     /* SDRAM controller */
>         /* XXX 405EP has no ECC interrupt */
> -    ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
> +    ppc4xx_sdram_init(env, qdev_get_gpio_in(uicdev, 17), 2, ram_memories,
>                       ram_bases, ram_sizes, do_init);
>     /* External bus controller */
>     ppc405_ebc_init(env);
>     /* DMA controller */
> -    dma_irqs[0] = pic[5];
> -    dma_irqs[1] = pic[6];
> -    dma_irqs[2] = pic[7];
> -    dma_irqs[3] = pic[8];
> +    dma_irqs[0] = qdev_get_gpio_in(uicdev, 5);
> +    dma_irqs[1] = qdev_get_gpio_in(uicdev, 6);
> +    dma_irqs[2] = qdev_get_gpio_in(uicdev, 7);
> +    dma_irqs[3] = qdev_get_gpio_in(uicdev, 8);
>     ppc405_dma_init(env, dma_irqs);
>     /* IIC controller */
> -    sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500, pic[2]);
> +    sysbus_create_simple(TYPE_PPC4xx_I2C, 0xef600500,
> +                         qdev_get_gpio_in(uicdev, 2));
>     /* GPIO */
>     ppc405_gpio_init(0xef600700);
>     /* Serial ports */
>     if (serial_hd(0) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
> +        serial_mm_init(address_space_mem, 0xef600300, 0,
> +                       qdev_get_gpio_in(uicdev, 0),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
>                        DEVICE_BIG_ENDIAN);
>     }
>     if (serial_hd(1) != NULL) {
> -        serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
> +        serial_mm_init(address_space_mem, 0xef600400, 0,
> +                       qdev_get_gpio_in(uicdev, 1),
>                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
>                        DEVICE_BIG_ENDIAN);
>     }
>     /* OCM */
>     ppc405_ocm_init(env);
>     /* GPT */
> -    gpt_irqs[0] = pic[19];
> -    gpt_irqs[1] = pic[20];
> -    gpt_irqs[2] = pic[21];
> -    gpt_irqs[3] = pic[22];
> -    gpt_irqs[4] = pic[23];
> +    gpt_irqs[0] = qdev_get_gpio_in(uicdev, 19);
> +    gpt_irqs[1] = qdev_get_gpio_in(uicdev, 20);
> +    gpt_irqs[2] = qdev_get_gpio_in(uicdev, 21);
> +    gpt_irqs[3] = qdev_get_gpio_in(uicdev, 22);
> +    gpt_irqs[4] = qdev_get_gpio_in(uicdev, 23);
>     ppc4xx_gpt_init(0xef600000, gpt_irqs);
>     /* PCI */
> -    /* Uses pic[3], pic[16], pic[18] */
> +    /* Uses UIC IRQs 3, 16, 18 */
>     /* MAL */
> -    mal_irqs[0] = pic[11];
> -    mal_irqs[1] = pic[12];
> -    mal_irqs[2] = pic[13];
> -    mal_irqs[3] = pic[14];
> +    mal_irqs[0] = qdev_get_gpio_in(uicdev, 11);
> +    mal_irqs[1] = qdev_get_gpio_in(uicdev, 12);
> +    mal_irqs[2] = qdev_get_gpio_in(uicdev, 13);
> +    mal_irqs[3] = qdev_get_gpio_in(uicdev, 14);
>     ppc4xx_mal_init(env, 4, 2, mal_irqs);
>     /* Ethernet */
> -    /* Uses pic[9], pic[15], pic[17] */
> +    /* Uses UIC IRQs 9, 15, 17 */
>     /* CPU control */
>     ppc405ep_cpc_init(env, clk_setup, sysclk);
>
> -- 
> 2.20.1
>
>
>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 4/8] hw/ppc/ppc440_bamboo: Drop use of ppcuic_init()
  2021-01-11  1:00   ` Nathan Chancellor
  2021-01-11 17:14     ` Peter Maydell
@ 2021-02-03 16:35     ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 39+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-03 16:35 UTC (permalink / raw)
  To: avocado-devel
  Cc: Peter Maydell, qemu-devel, qemu-ppc, Edgar E. Iglesias,
	Nathan Chancellor, David Gibson

Cc'ing avocado-devel for test idea.

On 1/11/21 2:00 AM, Nathan Chancellor wrote:
> On Sat, Dec 12, 2020 at 12:15:33AM +0000, Peter Maydell wrote:
>> Switch the bamboo board to directly creating and configuring the UIC,
>> rather than doing it via the old ppcuic_init() helper function.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/ppc/ppc440_bamboo.c | 38 +++++++++++++++++++++++++++-----------
>>  1 file changed, 27 insertions(+), 11 deletions(-)
...
> 
> Hopefully reporting this here is okay, I find Launchpad hard to use but
> I can file it there if need be.
> 
> This patch causes a panic while trying to boot a ppc44x_defconfig Linux
> kernel:
> 
> $ qemu-system-ppc \
>     -machine bamboo \
>     -no-reboot \
>     -append console=ttyS0 \
>     -display none \
>     -kernel uImage \
>     -m 128m \
>     -nodefaults \
>     -serial mon:stdio
> Linux version 5.11.0-rc3 (nathan@ubuntu-m3-large-x86) (powerpc-linux-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35) #1 Sun Jan 10 15:52:24 MST 2021
> Using PowerPC 44x Platform machine description
> ioremap() called early from find_legacy_serial_ports+0x64c/0x794. Use early_ioremap() instead
> printk: bootconsole [udbg0] enabled
> -----------------------------------------------------
> phys_mem_size     = 0x8000000
> dcache_bsize      = 0x20
> icache_bsize      = 0x20
> cpu_features      = 0x0000000000000100
>   possible        = 0x0000000040000100
>   always          = 0x0000000000000100
> cpu_user_features = 0x8c008000 0x00000000
> mmu_features      = 0x00000008
> -----------------------------------------------------
> Zone ranges:
>   Normal   [mem 0x0000000000000000-0x0000000007ffffff]
> Movable zone start for each node
> Early memory node ranges
>   node   0: [mem 0x0000000000000000-0x0000000007ffffff]
> Initmem setup node 0 [mem 0x0000000000000000-0x0000000007ffffff]
> MMU: Allocated 1088 bytes of context maps for 255 contexts
> Built 1 zonelists, mobility grouping on.  Total pages: 32448
> Kernel command line: console=ttyS0
> Dentry cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
> Inode-cache hash table entries: 8192 (order: 3, 32768 bytes, linear)
> mem auto-init: stack:off, heap alloc:off, heap free:off
> Memory: 122712K/131072K available (5040K kernel code, 236K rwdata, 1260K rodata, 200K init, 134K bss, 8360K reserved, 0K cma-reserved)
> Kernel virtual memory layout:
>   * 0xffbdf000..0xfffff000  : fixmap
>   * 0xffbdd000..0xffbdf000  : early ioremap
>   * 0xd1000000..0xffbdd000  : vmalloc & ioremap
> SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
> NR_IRQS: 512, nr_irqs: 512, preallocated irqs: 16
> Oops: Exception in kernel mode, sig: 4 [#1]
> BE PAGE_SIZE=4K PowerPC 44x Platform
> Modules linked in:
> CPU: 0 PID: 0 Comm: swapper Not tainted 5.11.0-rc3 #1
> NIP:  c0019e58 LR: c062e3a0 CTR: c0019e58
> REGS: c067fe90 TRAP: 0700   Not tainted  (5.11.0-rc3)
> MSR:  000a1000 <CE,ME>  CR: 84000224  XER: 20000000
> 
> GPR00: c062e370 c067ff50 c065c300 c0019e58 00000000 c0019238 c067fde0 c065c300
> GPR08: 00000000 00000000 c066fca4 00000066 84000222 00000000 00000000 00000000
> GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 c0000010 00000000
> GPR24: c0651594 c0651594 c0690000 c7ffe080 c0690000 c05c6f64 c0680000 c0802100
> NIP [c0019e58] __mtdcr_table+0xc20/0x3ff8
> LR [c062e3a0] uic_init_one+0x13c/0x214
> Call Trace:
> [c067ff50] [c062e370] uic_init_one+0x10c/0x214 (unreliable)
> [c067ff80] [c062e4f8] uic_init_tree+0x80/0x174
> [c067ffb0] [c0627af8] start_kernel+0x33c/0x508
> [c067fff0] [c0000044] _start+0x44/0x88
> Instruction dump:
> 7c9f2b86 4e800020 7c603286 4e800020 7c803386 4e800020 7c613286 4e800020
> 7c813386 4e800020 7c623286 4e800020 <7c823386> 4e800020 7c633286 4e800020
> random: get_random_bytes called from oops_exit+0x44/0x84 with crng_init=0
> ---[ end trace 0000000000000000 ]---
> 
> Kernel panic - not syncing: Attempted to kill the idle task!
> Rebooting in 180 seconds..
> 
> I have uploaded the kernel image here:
> 
> https://github.com/nathanchance/bug-files/blob/8edf230441bd8eda067973fdf0eb063c94f04379/qemu-0270d74ef886235051c13c39b0de88500c628a02/uImage
> 
> Do note that this is not the only commit that causes an issue on this
> machine, there is also a few assertion failures which I am about to
> report as well.
> 
> Cheers,
> Nathan
> 



^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2021-02-03 16:37 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-12  0:15 [PATCH 0/8] hw/ppc: Convert UIC device to QOM Peter Maydell
2020-12-12  0:15 ` [PATCH 1/8] hw/ppc/ppc4xx_devs: Make code style fixes to UIC code Peter Maydell
2020-12-13 12:09   ` Philippe Mathieu-Daudé
2020-12-13 14:33   ` Edgar E. Iglesias
2020-12-14  5:43   ` David Gibson
2020-12-14  9:15   ` Thomas Huth
2020-12-12  0:15 ` [PATCH 2/8] ppc: Convert PPC UIC to a QOM device Peter Maydell
2020-12-12 16:57   ` BALATON Zoltan via
2020-12-12 18:27   ` BALATON Zoltan via
2020-12-12 18:33     ` Peter Maydell
2020-12-12 19:53       ` BALATON Zoltan via
2020-12-13 14:34   ` Edgar E. Iglesias
2020-12-14  5:54   ` David Gibson
2020-12-14  9:12   ` BALATON Zoltan via
2020-12-12  0:15 ` [PATCH 3/8] hw/ppc/virtex_ml507: Drop use of ppcuic_init() Peter Maydell
2020-12-13 14:32   ` Edgar E. Iglesias
2020-12-14  5:55   ` David Gibson
2021-01-11 19:04   ` BALATON Zoltan
2020-12-12  0:15 ` [PATCH 4/8] hw/ppc/ppc440_bamboo: " Peter Maydell
2020-12-14  5:56   ` David Gibson
2021-01-11  1:00   ` Nathan Chancellor
2021-01-11 17:14     ` Peter Maydell
2021-01-11 18:22       ` Mark Cave-Ayland
2021-02-03 16:35     ` Philippe Mathieu-Daudé
2020-12-12  0:15 ` [PATCH 5/8] hw/ppc/sam460ex: " Peter Maydell
2020-12-12 17:17   ` BALATON Zoltan via
2020-12-12 18:11     ` Peter Maydell
2020-12-12 20:35       ` BALATON Zoltan via
2020-12-12 19:53   ` BALATON Zoltan via
2020-12-12 19:55     ` Peter Maydell
2020-12-12  0:15 ` [PATCH 6/8] hw/ppc: Delete unused ppc405cr_init() code Peter Maydell
2020-12-12  0:15 ` [PATCH 7/8] hw/ppc/ppc405_uc: Drop use of ppcuic_init() Peter Maydell
2021-01-11 19:09   ` BALATON Zoltan
2020-12-12  0:15 ` [PATCH 8/8] hw/ppc: Remove unused ppcuic_init() Peter Maydell
2020-12-13 14:35   ` Edgar E. Iglesias
2020-12-12 17:43 ` [PATCH 0/8] hw/ppc: Convert UIC device to QOM BALATON Zoltan via
2020-12-12 18:13   ` Peter Maydell
2020-12-14  6:00 ` David Gibson
2020-12-14 10:04   ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.