qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/5] kvm/powerpc: Enable MPIC for E500 platform


From: Paulev
Subject: Re: [Qemu-devel] [PATCH 1/5] kvm/powerpc: Enable MPIC for E500 platform.
Date: Thu, 19 Feb 2009 17:09:15 -0600

How do I remove myself from the QEMU list?

On Tue, Feb 17, 2009 at 3:59 AM, Liu Yu <address@hidden> wrote:
MPIC and OpenPIC have very similar design.
So a lot of code can be reused.

Modification mainly include:
1. keep struct openpic_t to the maximum size of both MPIC and OpenPIC.
2. endianess swap.
  MPIC has the same endianess as target, so no need to swap for MPIC.
3. using different init functions and function pointers for reset and irq raise.

Haven't test OpenPIC.

Signed-off-by: Liu Yu <address@hidden>
---
 hw/openpic.c      |  480 +++++++++++++++++++++++++++++++++++++++++++++--------
 hw/ppc_mac.h      |   13 --
 hw/ppc_newworld.c |    1 +
 3 files changed, 412 insertions(+), 82 deletions(-)

diff --git a/hw/openpic.c b/hw/openpic.c
index 6dfb590..0f687e4 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -35,6 +35,7 @@
 #include "hw.h"
 #include "ppc_mac.h"
 #include "pci.h"
+#include "openpic.h"

 //#define DEBUG_OPENPIC

@@ -60,14 +61,10 @@

 #define VID (0x00000000)

-#define OPENPIC_LITTLE_ENDIAN 1
-#define OPENPIC_BIG_ENDIAN    0
-
 #elif defined(USE_MPCxxx)

 #define MAX_CPU     2
-#define MAX_IRQ    64
-#define EXT_IRQ    48
+#define MAX_IRQ   128
 #define MAX_DBL     0
 #define MAX_MBX     0
 #define MAX_TMR     4
@@ -81,28 +78,55 @@ enum {
    IRQ_IDE,
 };

-#define OPENPIC_LITTLE_ENDIAN 1
-#define OPENPIC_BIG_ENDIAN    0
+/* OpenPIC */
+#define OPENPIC_MAX_CPU      2
+#define OPENPIC_MAX_IRQ     64
+#define OPENPIC_EXT_IRQ     48
+#define OPENPIC_MAX_TMR      MAX_TMR
+#define OPENPIC_MAX_IPI      MAX_IPI

+/* Interrupt definitions */
+#define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
+#define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
+#define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
+#if OPENPIC_MAX_IPI > 0
+#define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
+#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
 #else
-#error "Please select which OpenPic implementation is to be emulated"
+#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
+#define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
 #endif

-#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
-    (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
-#define OPENPIC_SWAP
-#endif
+/* MPIC */
+#define MPIC_MAX_CPU      1
+#define MPIC_MAX_EXT     12
+#define MPIC_MAX_INT     64
+#define MPIC_MAX_MSG      4
+#define MPIC_MAX_MSI      8
+#define MPIC_MAX_TMR      MAX_TMR
+#define MPIC_MAX_IPI      MAX_IPI
+#define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))

 /* Interrupt definitions */
-#define IRQ_FE     (EXT_IRQ)     /* Internal functional IRQ */
-#define IRQ_ERR    (EXT_IRQ + 1) /* Error IRQ */
-#define IRQ_TIM0   (EXT_IRQ + 2) /* First timer IRQ */
-#if MAX_IPI > 0
-#define IRQ_IPI0   (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
-#define IRQ_DBL0   (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
+#define MPIC_EXT_IRQ      0
+#define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
+#define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
+#define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
+#define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
+#define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
+
+#define MPIC_MAP_SIZE     0x40000
+
+enum mpic_ide_bits {
+    IDR_EP     = 0,
+    IDR_CI0     = 1,
+    IDR_CI1     = 2,
+    IDR_P1     = 30,
+    IDR_P0     = 31,
+};
+
 #else
-#define IRQ_DBL0   (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
-#define IRQ_MBX0   (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
+#error "Please select which OpenPic implementation is to be emulated"
 #endif

 #define BF_WIDTH(_bits_) \
@@ -157,6 +181,7 @@ enum IPVP_bits {
 #define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)

 typedef struct IRQ_dst_t {
+    uint32_t tfrr;
    uint32_t pctp; /* CPU current task priority */
    uint32_t pcsr; /* CPU sensitivity register */
    IRQ_queue_t raised;
@@ -200,8 +225,22 @@ typedef struct openpic_t {
 #endif
    /* IRQ out is used when in bypass mode (not implemented) */
    qemu_irq irq_out;
+    int max_irq;
+    int irq_ipi0;
+    int irq_tim0;
+    int need_swap;
+    void (*reset) (void *);
+    void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
 } openpic_t;

+static inline uint32_t openpic_swap32(openpic_t *opp, uint32_t val)
+{
+    if (opp->need_swap)
+        return bswap32(val);
+
+    return val;
+}
+
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 {
    set_bit(q->queue, n_IRQ);
@@ -224,7 +263,7 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)

    next = -1;
    priority = -1;
-    for (i = 0; i < MAX_IRQ; i++) {
+    for (i = 0; i < opp->max_irq; i++) {
       if (IRQ_testbit(q, i)) {
            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
@@ -286,7 +325,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
        return;
    }
    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
-    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+    opp->irq_raise(opp, n_CPU, src);
 }

 /* update pic state because registers for n_IRQ have changed value */
@@ -374,7 +413,7 @@ static void openpic_reset (void *opaque)

    opp->glbc = 0x80000000;
    /* Initialise controller registers */
-    opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
+    opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
    opp->veni = VENI;
    opp->pint = 0x00000000;
    opp->spve = 0x000000FF;
@@ -382,7 +421,7 @@ static void openpic_reset (void *opaque)
    /* ? */
    opp->micr = 0x00000000;
    /* Initialise IRQ sources */
-    for (i = 0; i < MAX_IRQ; i++) {
+    for (i = 0; i < opp->max_irq; i++) {
       opp->src[i].ipvp = 0xA0000000;
       opp->src[i].ide  = 0x00000000;
    }
@@ -544,16 +583,16 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
    if (addr & 0xF)
        return;
-#if defined OPENPIC_SWAP
-    val = bswap32(val);
+#if defined TARGET_WORDS_BIGENDIAN
+    val = openpic_swap32(opp, val);
 #endif
    addr &= 0xFF;
    switch (addr) {
    case 0x00: /* FREP */
        break;
    case 0x20: /* GLBC */
-        if (val & 0x80000000)
-            openpic_reset(opp);
+        if (val & 0x80000000 && opp->reset)
+            opp->reset(opp);
        opp->glbc = val & ~0x80000000;
       break;
    case 0x80: /* VENI */
@@ -580,7 +619,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
        {
            int idx;
            idx = (addr - 0xA0) >> 4;
-            write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
+            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
        }
        break;
 #endif
@@ -626,7 +665,7 @@ static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
        {
            int idx;
            idx = (addr - 0xA0) >> 4;
-            retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
+            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
        }
       break;
 #endif
@@ -640,8 +679,8 @@ static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
        break;
    }
    DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
-    retval = bswap32(retval);
+#if defined TARGET_WORDS_BIGENDIAN
+    retval = openpic_swap32(opp, retval);
 #endif

    return retval;
@@ -655,8 +694,8 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
    if (addr & 0xF)
        return;
-#if defined OPENPIC_SWAP
-    val = bswap32(val);
+#if defined TARGET_WORDS_BIGENDIAN
+    val = openpic_swap32(opp, val);
 #endif
    addr -= 0x1100;
    addr &= 0xFFFF;
@@ -673,10 +712,10 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
       opp->timers[idx].tibc = val;
       break;
    case 0x20: /* TIVP */
-       write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
+        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
       break;
    case 0x30: /* TIDE */
-       write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
+        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
       break;
    }
 }
@@ -703,15 +742,15 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
       retval = opp->timers[idx].tibc;
       break;
    case 0x20: /* TIPV */
-       retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
+        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
       break;
    case 0x30: /* TIDE */
-       retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
+        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
       break;
    }
    DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
-    retval = bswap32(retval);
+#if defined TARGET_WORDS_BIGENDIAN
+    retval = openpic_swap32(opp, retval);
 #endif

    return retval;
@@ -725,8 +764,8 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
    if (addr & 0xF)
        return;
-#if defined OPENPIC_SWAP
-    val = tswap32(val);
+#if defined TARGET_WORDS_BIGENDIAN
+    val = openpic_swap32(opp, val);
 #endif
    addr = addr & 0xFFF0;
    idx = addr >> 5;
@@ -759,8 +798,8 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr)
        retval = read_IRQreg(opp, idx, IRQ_IPVP);
    }
    DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
-    retval = tswap32(retval);
+#if defined TARGET_WORDS_BIGENDIAN
+    retval = openpic_swap32(opp, retval);
 #endif

    return retval;
@@ -776,8 +815,8 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
    if (addr & 0xF)
        return;
-#if defined OPENPIC_SWAP
-    val = bswap32(val);
+#if defined TARGET_WORDS_BIGENDIAN
+    val = openpic_swap32(opp, val);
 #endif
    addr &= 0x1FFF0;
    idx = addr / 0x1000;
@@ -790,9 +829,9 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
    case 0x60:
    case 0x70:
        idx = (addr - 0x40) >> 4;
-        write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
-        openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
-        openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
+        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
        break;
 #endif
    case 0x80: /* PCTP */
@@ -819,7 +858,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
                    idx, n_IRQ);
-            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+            opp->irq_raise(opp, idx, src);
        }
       break;
    default:
@@ -889,15 +928,15 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
    case 0x40: /* IDE */
    case 0x50:
        idx = (addr - 0x40) >> 4;
-        retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
+        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
        break;
 #endif
    default:
        break;
    }
    DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
-    retval= bswap32(retval);
+#if defined TARGET_WORDS_BIGENDIAN
+    retval = openpic_swap32(opp, retval);
 #endif

    return retval;
@@ -989,7 +1028,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
    /* Interrupt source registers */
    DPRINTF("Register OPENPIC src   %08x => %08x\n",
-            addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
+            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
    /* Per CPU registers */
    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
@@ -1026,7 +1065,7 @@ static void openpic_save(QEMUFile* f, void *opaque)
    qemu_put_be32s(f, &opp->spve);
    qemu_put_be32s(f, &opp->tifr);

-    for (i = 0; i < MAX_IRQ; i++) {
+    for (i = 0; i < opp->max_irq; i++) {
        qemu_put_be32s(f, &opp->src[i].ipvp);
        qemu_put_be32s(f, &opp->src[i].ide);
        qemu_put_sbe32s(f, &opp->src[i].type);
@@ -1034,15 +1073,16 @@ static void openpic_save(QEMUFile* f, void *opaque)
        qemu_put_sbe32s(f, &opp->src[i].pending);
    }

-    for (i = 0; i < MAX_IRQ; i++) {
+    qemu_put_sbe32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_put_be32s(f, &opp->dst[i].tfrr);
        qemu_put_be32s(f, &opp->dst[i].pctp);
        qemu_put_be32s(f, &opp->dst[i].pcsr);
        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
    }

-    qemu_put_sbe32s(f, &opp->nb_cpus);
-
    for (i = 0; i < MAX_TMR; i++) {
        qemu_put_be32s(f, &opp->timers[i].ticc);
        qemu_put_be32s(f, &opp->timers[i].tibc);
@@ -1092,7 +1132,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
    qemu_get_be32s(f, &opp->spve);
    qemu_get_be32s(f, &opp->tifr);

-    for (i = 0; i < MAX_IRQ; i++) {
+    for (i = 0; i < opp->max_irq; i++) {
        qemu_get_be32s(f, &opp->src[i].ipvp);
        qemu_get_be32s(f, &opp->src[i].ide);
        qemu_get_sbe32s(f, &opp->src[i].type);
@@ -1100,15 +1140,16 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
        qemu_get_sbe32s(f, &opp->src[i].pending);
    }

-    for (i = 0; i < MAX_IRQ; i++) {
+    qemu_get_sbe32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_get_be32s(f, &opp->dst[i].tfrr);
        qemu_get_be32s(f, &opp->dst[i].pctp);
        qemu_get_be32s(f, &opp->dst[i].pcsr);
        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
    }

-    qemu_get_sbe32s(f, &opp->nb_cpus);
-
    for (i = 0; i < MAX_TMR; i++) {
        qemu_get_be32s(f, &opp->timers[i].ticc);
        qemu_get_be32s(f, &opp->timers[i].tibc);
@@ -1131,6 +1172,11 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
    return pci_device_load(&opp->pci_dev, f);
 }

+static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
+{
+    qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+}
+
 qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
                        qemu_irq **irqs, qemu_irq irq_out)
 {
@@ -1164,33 +1210,329 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,

    //    isu_base &= 0xFFFC0000;
    opp->nb_cpus = nb_cpus;
+    opp->max_irq = OPENPIC_MAX_IRQ;
+    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
+    opp->irq_tim0 = OPENPIC_IRQ_TIM0;
    /* Set IRQ types */
-    for (i = 0; i < EXT_IRQ; i++) {
+    for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
        opp->src[i].type = IRQ_EXTERNAL;
    }
-    for (; i < IRQ_TIM0; i++) {
+    for (; i < OPENPIC_IRQ_TIM0; i++) {
        opp->src[i].type = IRQ_SPECIAL;
    }
 #if MAX_IPI > 0
-    m = IRQ_IPI0;
+    m = OPENPIC_IRQ_IPI0;
 #else
-    m = IRQ_DBL0;
+    m = OPENPIC_IRQ_DBL0;
 #endif
    for (; i < m; i++) {
        opp->src[i].type = IRQ_TIMER;
    }
-    for (; i < MAX_IRQ; i++) {
+    for (; i < OPENPIC_MAX_IRQ; i++) {
        opp->src[i].type = IRQ_INTERNAL;
    }
    for (i = 0; i < nb_cpus; i++)
        opp->dst[i].irqs = irqs[i];
    opp->irq_out = irq_out;
+    opp->need_swap = 1;

    register_savevm("openpic", 0, 1, openpic_save, openpic_load, opp);
    qemu_register_reset(openpic_reset, opp);
-    openpic_reset(opp);
+
+    opp->irq_raise = openpic_irq_raise;
+    opp->reset = openpic_reset;
+
+    opp->reset(opp);
    if (pmem_index)
        *pmem_index = opp->mem_index;

-    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
+    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
+}
+
+static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
+{
+    int n_ci = IDR_CI0 - n_CPU;
+    DPRINTF("%s: cpu:%d irq:%d (testbit idr:%x ci:%d)\n", __func__,
+                    n_CPU, n_IRQ, mpp->src[n_IRQ].ide, n_ci);
+    if(test_bit(&src->ide, n_ci)) {
+        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
+    }
+    else {
+        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+    }
+}
+
+static void mpic_reset (void *opaque)
+{
+    openpic_t *mpp = (openpic_t *)opaque;
+    int i;
+
+    mpp->glbc = 0x80000000;
+    /* Initialise controller registers */
+    mpp->frep = 0x004f0002;
+    mpp->veni = VENI;
+    mpp->pint = 0x00000000;
+    mpp->spve = 0x0000FFFF;
+    /* Initialise IRQ sources */
+    for (i = 0; i < mpp->max_irq; i++) {
+        mpp->src[i].ipvp = 0x80800000;
+        mpp->src[i].ide  = 0x00000001;
+    }
+    /* Initialise IRQ destinations */
+    for (i = 0; i < MAX_CPU; i++) {
+        mpp->dst[i].pctp      = 0x0000000F;
+        mpp->dst[i].tfrr      = 0x00000000;
+        memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
+        mpp->dst[i].raised.next = -1;
+        memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
+        mpp->dst[i].servicing.next = -1;
+    }
+    /* Initialise timers */
+    for (i = 0; i < MAX_TMR; i++) {
+        mpp->timers[i].ticc = 0x00000000;
+        mpp->timers[i].tibc = 0x80000000;
+    }
+    /* Go out of RESET state */
+    mpp->glbc = 0x00000000;
+}
+
+static void mpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx, cpu;
+
+    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr &= 0xFFFF;
+    cpu = addr >> 12;
+    idx = (addr >> 6) & 0x3;
+    switch (addr & 0x30) {
+    case 0x00: /* gtccr */
+        break;
+    case 0x10: /* gtbcr */
+        if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
+            (val & 0x80000000) == 0 &&
+            (mpp->timers[idx].tibc & 0x80000000) != 0)
+            mpp->timers[idx].ticc &= ~0x80000000;
+        mpp->timers[idx].tibc = val;
+        break;
+    case 0x20: /* GTIVPR */
+        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
+        break;
+    case 0x30: /* GTIDR & TFRR */
+        if ((addr & 0xF0) == 0xF0)
+            mpp->dst[cpu].tfrr = val;
+        else
+            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
+        break;
+    }
+}
+
+static uint32_t mpic_timer_read (void *opaque, uint32_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx, cpu;
+
+    DPRINTF("%s: addr %08x\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr &= 0xFFFF;
+    cpu = addr >> 12;
+    idx = (addr >> 6) & 0x3;
+    switch (addr & 0x30) {
+    case 0x00: /* gtccr */
+        retval = mpp->timers[idx].ticc;
+        break;
+    case 0x10: /* gtbcr */
+        retval = mpp->timers[idx].tibc;
+        break;
+    case 0x20: /* TIPV */
+        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
+        break;
+    case 0x30: /* TIDR */
+        if ((addr &0xF0) == 0XF0)
+            retval = mpp->dst[cpu].tfrr;
+        else
+            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
+        break;
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void mpic_src_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    openpic_t *mpp = opaque;
+    int idx;
+
+    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
+    if (addr & 0xF)
+        return;
+    addr = addr & 0xFFF0;
+    if (addr < 0x180) {
+        idx = MPIC_EXT_IRQ;
+    } else if (addr >= 0x200 && addr < 0xa00) {
+        idx = MPIC_INT_IRQ;
+        addr -= 0x200;
+    } else if (addr >= 0x1600 && addr < 0x1700) {
+        idx = MPIC_MSG_IRQ;
+        addr -= 0x1600;
+    } else if (addr >= 0x1C00 && addr < 0x1D00) {
+        idx = MPIC_MSI_IRQ;
+        addr -= 0x1C00;
+    } else {
+        return;
+    }
+    idx += addr >> 5;
+    if (addr & 0x10) {
+        /* EXDE / IFEDE / IEEDE */
+        write_IRQreg(mpp, idx, IRQ_IDE, val);
+    } else {
+        /* EXVP / IFEVP / IEEVP */
+        write_IRQreg(mpp, idx, IRQ_IPVP, val);
+    }
+}
+
+static uint32_t mpic_src_read (void *opaque, uint32_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval;
+    int idx;
+
+    DPRINTF("%s: addr %08x\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF)
+        return retval;
+    addr = addr & 0xFFF0;
+    if (addr < 0x180) {
+        idx = MPIC_EXT_IRQ;
+    } else if (addr >= 0x200 && addr < 0xa00) {
+        idx = MPIC_INT_IRQ;
+        addr -= 0x200;
+    } else if (addr >= 0x1600 && addr < 0x1700) {
+        idx = MPIC_MSG_IRQ;
+        addr -= 0x1600;
+    } else if (addr >= 0x1C00 && addr < 0x1D00) {
+        idx = MPIC_MSI_IRQ;
+        addr -= 0x1C00;
+    } else {
+        return retval;
+    }
+    idx += addr >> 5;
+    if (addr & 0x10) {
+        /* EXDE / IFEDE / IEEDE */
+        retval = read_IRQreg(mpp, idx, IRQ_IDE);
+    } else {
+        /* EXVP / IFEVP / IEEVP */
+        retval = read_IRQreg(mpp, idx, IRQ_IPVP);
+    }
+    DPRINTF("%s: => %08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void mpic_writel (void *opaque,
+                            target_phys_addr_t addr, uint32_t val)
+{
+    openpic_t *mpp = opaque;
+
+    addr &= 0x3FFFF;
+    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
+    if (addr < 0x10F0) {
+        /* Global registers */
+        openpic_gbl_write(mpp, addr, val);
+    } else if (addr < 0x10000) {
+        /* Timers registers */
+        mpic_timer_write(mpp, addr, val);
+    } else if (addr < 0x20000) {
+        /* Source registers */
+        mpic_src_write(mpp, addr, val);
+    } else if (addr < 0x30000){
+        /* CPU registers */
+        openpic_cpu_write(mpp, addr, val);
+    } else {
+        DPRINTF("wrong mpic write addr %p\n",addr);
+    }
+}
+
+static uint32_t mpic_readl (void *opaque,target_phys_addr_t addr)
+{
+    openpic_t *mpp = opaque;
+    uint32_t retval = 0;
+
+    addr &= 0x3FFFF;
+    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
+    if (addr < 0x10F0) {
+        /* Global registers */
+        retval = openpic_gbl_read(mpp, addr);
+    } else if (addr < 0x10000) {
+        /* Timers registers */
+        retval = mpic_timer_read(mpp, addr);
+    } else if (addr < 0x20000) {
+        /* Source registers */
+        retval = mpic_src_read(mpp, addr);
+    } else if (addr < 0x30000){
+        /* CPU registers */
+        retval = openpic_cpu_read(mpp, addr);
+    } else {
+        DPRINTF("wrong mpic read addr %p\n",addr);
+    }
+
+    return retval;
+}
+
+static CPUWriteMemoryFunc *mpic_write[] = {
+    &openpic_buggy_write,
+    &openpic_buggy_write,
+    &mpic_writel,
+};
+
+static CPUReadMemoryFunc *mpic_read[] = {
+    &openpic_buggy_read,
+    &openpic_buggy_read,
+    &mpic_readl,
+};
+
+qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out)
+{
+    openpic_t *mpp;
+    int i;
+
+    /* XXX: for now, only one CPU is supported */
+    if (nb_cpus != 1)
+        return NULL;
+
+    mpp = qemu_mallocz(sizeof(openpic_t));
+
+    mpp->mem_index = cpu_register_io_memory(0, mpic_read, mpic_write, mpp);
+    if (mpp->mem_index < 0)
+        goto free;
+    cpu_register_physical_memory(base, MPIC_MAP_SIZE, mpp->mem_index);
+
+    mpp->nb_cpus = nb_cpus;
+    mpp->max_irq = MPIC_MAX_IRQ;
+    mpp->irq_ipi0 = MPIC_IPI_IRQ;
+    mpp->irq_tim0 = MPIC_TMR_IRQ;
+
+    for (i = 0; i < nb_cpus; i++)
+        mpp->dst[i].irqs = irqs[i];
+    mpp->irq_out = irq_out;
+    mpp->need_swap = 0;    /* MPIC has the same endian as target */
+
+    mpp->irq_raise = mpic_irq_raise;
+    mpp->reset = mpic_reset;
+
+    register_savevm("mpic", 0, 1, openpic_save, openpic_load,  mpp);
+    mpp->reset(mpp);
+
+    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
+
+free:
+    qemu_free(mpp);
+    return NULL;
 }
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 5851a5e..df148b2 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -112,17 +112,4 @@ void adb_mouse_init(ADBBusState *bus);

 extern ADBBusState adb_bus;

-/* openpic.c */
-/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
-enum {
-    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
-    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
-    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
-    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
-    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
-    OPENPIC_OUTPUT_NB,
-};
-qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
-                        qemu_irq **irqs, qemu_irq irq_out);
-
 #endif /* !defined(__PPC_MAC_H__) */
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 6f60e49..b285864 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -34,6 +34,7 @@
 #include "boards.h"
 #include "fw_cfg.h"
 #include "escc.h"
+#include "openpic.h"

 #define MAX_IDE_BUS 2
 #define VGA_BIOS_SIZE 65536
--
1.5.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]