Commit d0b72631 authored by Alexander Graf's avatar Alexander Graf
Browse files

openpic: convert to qdev



This patch converts the OpenPIC device to qdev. Along the way it
renames the "openpic" target to "raven" and the "mpic" target to
"fsl_mpic_20", to better reflect the actual models they implement.

This way we have a generic OpenPIC device now that can handle
different flavors of the OpenPIC specification.

Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 5bac0701
Loading
Loading
Loading
Loading
+136 −142
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "ppc_mac.h"
#include "pci.h"
#include "openpic.h"
#include "sysbus.h"

//#define DEBUG_OPENPIC

@@ -54,30 +55,10 @@
#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
#define VID         0x03 /* MPIC version ID */

enum {
    IRQ_IPVP = 0,
    IRQ_IDE,
};

/* 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
#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
/* OpenPIC capability flags */
#define OPENPIC_FLAG_IDE_CRIT     (1 << 0)

/* OpenPIC address map */
#define OPENPIC_GLB_REG_START        0x0
#define OPENPIC_GLB_REG_SIZE         0x10F0
#define OPENPIC_TMR_REG_START        0x10F0
@@ -87,31 +68,37 @@ enum {
#define OPENPIC_CPU_REG_START        0x20000
#define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)

/* MPIC */
#define MPIC_MAX_CPU      1
#define MPIC_MAX_EXT     12
#define MPIC_MAX_INT     64
#define MPIC_MAX_IRQ     MAX_IRQ
/* Raven */
#define RAVEN_MAX_CPU      2
#define RAVEN_MAX_EXT     48
#define RAVEN_MAX_IRQ     64
#define RAVEN_MAX_TMR      MAX_TMR
#define RAVEN_MAX_IPI      MAX_IPI

/* Interrupt definitions */
#define RAVEN_FE_IRQ     (RAVEN_MAX_EXT)     /* Internal functional IRQ */
#define RAVEN_ERR_IRQ    (RAVEN_MAX_EXT + 1) /* Error IRQ */
#define RAVEN_TMR_IRQ    (RAVEN_MAX_EXT + 2) /* First timer IRQ */
#define RAVEN_IPI_IRQ    (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
/* First doorbell IRQ */
#define RAVEN_DBL_IRQ    (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))

/* FSL_MPIC_20 */
#define FSL_MPIC_20_MAX_CPU      1
#define FSL_MPIC_20_MAX_EXT     12
#define FSL_MPIC_20_MAX_INT     64
#define FSL_MPIC_20_MAX_IRQ     MAX_IRQ

/* Interrupt definitions */
/* IRQs, accessible through the IRQ region */
#define MPIC_EXT_IRQ      0x00
#define MPIC_INT_IRQ      0x10
#define MPIC_MSG_IRQ      0xb0
#define MPIC_MSI_IRQ      0xe0
#define FSL_MPIC_20_EXT_IRQ      0x00
#define FSL_MPIC_20_INT_IRQ      0x10
#define FSL_MPIC_20_MSG_IRQ      0xb0
#define FSL_MPIC_20_MSI_IRQ      0xe0
/* These are available through separate regions, but
   for simplicity's sake mapped into the same number space */
#define MPIC_TMR_IRQ      0x100
#define MPIC_IPI_IRQ      0x104

#define MPIC_GLB_REG_START        0x0
#define MPIC_GLB_REG_SIZE         0x10F0
#define MPIC_TMR_REG_START        0x10F0
#define MPIC_TMR_REG_SIZE         0x220
#define MPIC_SRC_REG_START        0x10000
#define MPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
#define MPIC_CPU_REG_START        0x20000
#define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
#define FSL_MPIC_20_TMR_IRQ      0x100
#define FSL_MPIC_20_IPI_IRQ      0x104

/*
 * Block Revision Register1 (BRR1): QEMU does not fully emulate
@@ -129,6 +116,7 @@ enum {
#define FREP_VID_SHIFT     0

#define VID_REVISION_1_2   2
#define VID_REVISION_1_3   3

#define VENI_GENERIC      0x00000000 /* Generic Vendor ID */

@@ -205,10 +193,11 @@ typedef struct IRQ_dst_t {
} IRQ_dst_t;

typedef struct OpenPICState {
    PCIDevice pci_dev;
    SysBusDevice busdev;
    MemoryRegion mem;

    /* Behavior control */
    uint32_t model;
    uint32_t flags;
    uint32_t nb_irqs;
    uint32_t vid;
@@ -231,15 +220,15 @@ typedef struct OpenPICState {
    IRQ_src_t src[MAX_IRQ];
    /* Local registers per output pin */
    IRQ_dst_t dst[MAX_CPU];
    int nb_cpus;
    uint32_t nb_cpus;
    /* Timer registers */
    struct {
        uint32_t ticc;  /* Global timer current count register */
        uint32_t tibc;  /* Global timer base count register */
    } timers[MAX_TMR];
    int max_irq;
    int irq_ipi0;
    int irq_tim0;
    uint32_t max_irq;
    uint32_t irq_ipi0;
    uint32_t irq_tim0;
} OpenPICState;

static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src);
@@ -411,9 +400,9 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level)
    openpic_update_irq(opp, n_IRQ);
}

static void openpic_reset (void *opaque)
static void openpic_reset(DeviceState *d)
{
    OpenPICState *opp = (OpenPICState *)opaque;
    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d));
    int i;

    opp->glbc = 0x80000000;
@@ -506,7 +495,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
        break;
    case 0x1020: /* GLBC */
        if (val & 0x80000000) {
            openpic_reset(opp);
            openpic_reset(&opp->busdev.qdev);
        }
        break;
    case 0x1080: /* VENI */
@@ -971,7 +960,7 @@ static void openpic_save(QEMUFile* f, void *opaque)
        qemu_put_sbe32s(f, &opp->src[i].pending);
    }

    qemu_put_sbe32s(f, &opp->nb_cpus);
    qemu_put_be32s(f, &opp->nb_cpus);

    for (i = 0; i < opp->nb_cpus; i++) {
        qemu_put_be32s(f, &opp->dst[i].pctp);
@@ -984,8 +973,6 @@ static void openpic_save(QEMUFile* f, void *opaque)
        qemu_put_be32s(f, &opp->timers[i].ticc);
        qemu_put_be32s(f, &opp->timers[i].tibc);
    }

    pci_device_save(&opp->pci_dev, f);
}

static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
@@ -1020,7 +1007,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
        qemu_get_sbe32s(f, &opp->src[i].pending);
    }

    qemu_get_sbe32s(f, &opp->nb_cpus);
    qemu_get_be32s(f, &opp->nb_cpus);

    for (i = 0; i < opp->nb_cpus; i++) {
        qemu_get_be32s(f, &opp->dst[i].pctp);
@@ -1034,7 +1021,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
        qemu_get_be32s(f, &opp->timers[i].tibc);
    }

    return pci_device_load(&opp->pci_dev, f);
    return 0;
}

static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src)
@@ -1048,17 +1035,18 @@ static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src)
    }
}

qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
                        qemu_irq **irqs)
{
    OpenPICState *opp;
    int i;
    struct {
struct memreg {
    const char             *name;
    MemoryRegionOps const  *ops;
    hwaddr      start_addr;
    ram_addr_t              size;
    } const list[] = {
};

static int openpic_init(SysBusDevice *dev)
{
    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
    int i, j;
    const struct memreg list_le[] = {
        {"glb", &openpic_glb_ops_le, OPENPIC_GLB_REG_START,
                                     OPENPIC_GLB_REG_SIZE},
        {"tmr", &openpic_tmr_ops_le, OPENPIC_TMR_REG_START,
@@ -1068,16 +1056,57 @@ qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
        {"cpu", &openpic_cpu_ops_le, OPENPIC_CPU_REG_START,
                                     OPENPIC_CPU_REG_SIZE},
    };
    const struct memreg list_be[] = {
        {"glb", &openpic_glb_ops_be, OPENPIC_GLB_REG_START,
                                     OPENPIC_GLB_REG_SIZE},
        {"tmr", &openpic_tmr_ops_be, OPENPIC_TMR_REG_START,
                                     OPENPIC_TMR_REG_SIZE},
        {"src", &openpic_src_ops_be, OPENPIC_SRC_REG_START,
                                     OPENPIC_SRC_REG_SIZE},
        {"cpu", &openpic_cpu_ops_be, OPENPIC_CPU_REG_START,
                                     OPENPIC_CPU_REG_SIZE},
    };
    struct memreg const *list;

    /* XXX: for now, only one CPU is supported */
    if (nb_cpus != 1)
        return NULL;
    opp = g_malloc0(sizeof(OpenPICState));
    switch (opp->model) {
    case OPENPIC_MODEL_FSL_MPIC_20:
    default:
        opp->flags |= OPENPIC_FLAG_IDE_CRIT;
        opp->nb_irqs = 80;
        opp->vid = VID_REVISION_1_2;
        opp->veni = VENI_GENERIC;
        opp->spve_mask = 0xFFFF;
        opp->tifr_reset = 0x00000000;
        opp->ipvp_reset = 0x80000000;
        opp->ide_reset = 0x00000001;
        opp->max_irq = FSL_MPIC_20_MAX_IRQ;
        opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ;
        opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ;
        list = list_be;
        break;
    case OPENPIC_MODEL_RAVEN:
        opp->nb_irqs = RAVEN_MAX_EXT;
        opp->vid = VID_REVISION_1_3;
        opp->veni = VENI_GENERIC;
        opp->spve_mask = 0xFF;
        opp->tifr_reset = 0x003F7A00;
        opp->ipvp_reset = 0xA0000000;
        opp->ide_reset = 0x00000000;
        opp->max_irq = RAVEN_MAX_IRQ;
        opp->irq_ipi0 = RAVEN_IPI_IRQ;
        opp->irq_tim0 = RAVEN_TMR_IRQ;
        list = list_le;

        /* Only UP supported today */
        if (opp->nb_cpus != 1) {
            return -EINVAL;
        }
        break;
    }

    memory_region_init(&opp->mem, "openpic", 0x40000);

    for (i = 0; i < ARRAY_SIZE(list); i++) {

    for (i = 0; i < ARRAY_SIZE(list_le); i++) {
        memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp,
                              list[i].name, list[i].size);

@@ -1085,83 +1114,48 @@ qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
                                    &opp->sub_io_mem[i]);
    }

    //    isu_base &= 0xFFFC0000;
    opp->nb_cpus = nb_cpus;
    opp->nb_irqs = OPENPIC_EXT_IRQ;
    opp->vid = VID;
    opp->veni = VENI_GENERIC;
    opp->spve_mask = 0xFF;
    opp->tifr_reset = 0x003F7A00;
    opp->max_irq = OPENPIC_MAX_IRQ;
    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
    opp->irq_tim0 = OPENPIC_IRQ_TIM0;

    for (i = 0; i < nb_cpus; i++)
        opp->dst[i].irqs = irqs[i];
    for (i = 0; i < opp->nb_cpus; i++) {
        opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
            sysbus_init_irq(dev, &opp->dst[i].irqs[j]);
        }
    }

    register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
    register_savevm(&opp->busdev.qdev, "openpic", 0, 2,
                    openpic_save, openpic_load, opp);
    qemu_register_reset(openpic_reset, opp);

    if (pmem)
        *pmem = &opp->mem;
    sysbus_init_mmio(dev, &opp->mem);
    qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq);

    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
    return 0;
}

qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
                     int nb_cpus, qemu_irq **irqs)
{
    OpenPICState    *mpp;
    int           i;
    struct {
        const char             *name;
        MemoryRegionOps const  *ops;
        hwaddr      start_addr;
        ram_addr_t              size;
    } const list[] = {
        {"glb", &openpic_glb_ops_be, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
        {"tmr", &openpic_tmr_ops_be, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
        {"src", &openpic_src_ops_be, MPIC_SRC_REG_START, MPIC_SRC_REG_SIZE},
        {"cpu", &openpic_cpu_ops_be, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
static Property openpic_properties[] = {
    DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
    DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
    DEFINE_PROP_END_OF_LIST(),
};

    mpp = g_malloc0(sizeof(OpenPICState));

    memory_region_init(&mpp->mem, "mpic", 0x40000);
    memory_region_add_subregion(address_space, base, &mpp->mem);

    for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {

        memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
                              list[i].name, list[i].size);
static void openpic_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

        memory_region_add_subregion(&mpp->mem, list[i].start_addr,
                                    &mpp->sub_io_mem[i]);
    k->init = openpic_init;
    dc->props = openpic_properties;
    dc->reset = openpic_reset;
}

    mpp->nb_cpus = nb_cpus;
    /* 12 external sources, 48 internal sources , 4 timer sources,
       4 IPI sources, 4 messaging sources, and 8 Shared MSI sources */
    mpp->nb_irqs = 80;
    mpp->vid = VID_REVISION_1_2;
    mpp->veni = VENI_GENERIC;
    mpp->spve_mask = 0xFFFF;
    mpp->tifr_reset = 0x00000000;
    mpp->ipvp_reset = 0x80000000;
    mpp->ide_reset = 0x00000001;
    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];

    /* Enable critical interrupt support */
    mpp->flags |= OPENPIC_FLAG_IDE_CRIT;

    register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
    qemu_register_reset(openpic_reset, mpp);
static TypeInfo openpic_info = {
    .name          = "openpic",
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(OpenPICState),
    .class_init    = openpic_class_init,
};

    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
static void openpic_register_types(void)
{
    type_register_static(&openpic_info);
}

type_init(openpic_register_types)
+2 −6
Original line number Diff line number Diff line
@@ -11,11 +11,7 @@ enum {
    OPENPIC_OUTPUT_NB,
};

/* OpenPIC capability flags */
#define OPENPIC_FLAG_IDE_CRIT    (1 << 0)
#define OPENPIC_MODEL_RAVEN       0
#define OPENPIC_MODEL_FSL_MPIC_20 1

qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
                        qemu_irq **irqs);
qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
                     int nb_cpus, qemu_irq **irqs);
#endif /* __OPENPIC_H__ */
+19 −5
Original line number Diff line number Diff line
@@ -418,7 +418,7 @@ void ppce500_init(PPCE500Params *params)
    target_ulong dt_base = 0;
    target_ulong initrd_base = 0;
    target_long initrd_size=0;
    int i=0;
    int i = 0, j, k;
    unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
    qemu_irq **irqs, *mpic;
    DeviceState *dev;
@@ -492,13 +492,27 @@ void ppce500_init(PPCE500Params *params)
                                ccsr_addr_space);

    /* MPIC */
    mpic = mpic_init(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET,
                     smp_cpus, irqs);
    mpic = g_new(qemu_irq, 256);
    dev = qdev_create(NULL, "openpic");
    qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
    qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_FSL_MPIC_20);
    qdev_init_nofail(dev);
    s = sysbus_from_qdev(dev);

    k = 0;
    for (i = 0; i < smp_cpus; i++) {
        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
            sysbus_connect_irq(s, k++, irqs[i][j]);
        }
    }

    if (!mpic) {
        cpu_abort(env, "MPIC failed to initialize\n");
    for (i = 0; i < 256; i++) {
        mpic[i] = qdev_get_gpio_in(dev, i);
    }

    memory_region_add_subregion(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET,
                                s->mmio[0].memory);

    /* Serial */
    if (serial_hds[0]) {
        serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
+23 −2
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#include "hw/usb.h"
#include "blockdev.h"
#include "exec-memory.h"
#include "sysbus.h"

#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
@@ -141,7 +142,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
    char *filename;
    qemu_irq *pic, **openpic_irqs;
    MemoryRegion *unin_memory = g_new(MemoryRegion, 1);
    int linux_boot, i;
    int linux_boot, i, j, k;
    MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
    hwaddr kernel_base, initrd_base, cmdline_base = 0;
    long kernel_size, initrd_size;
@@ -156,6 +157,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
    void *fw_cfg;
    void *dbdma;
    int machine_arch;
    SysBusDevice *s;
    DeviceState *dev;

    linux_boot = (kernel_filename != NULL);

@@ -320,7 +323,25 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
            exit(1);
        }
    }
    pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs);

    pic = g_new(qemu_irq, 64);

    dev = qdev_create(NULL, "openpic");
    qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN);
    qdev_init_nofail(dev);
    s = sysbus_from_qdev(dev);
    pic_mem = s->mmio[0].memory;
    k = 0;
    for (i = 0; i < smp_cpus; i++) {
        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
            sysbus_connect_irq(s, k++, openpic_irqs[i][j]);
        }
    }

    for (i = 0; i < 64; i++) {
        pic[i] = qdev_get_gpio_in(dev, i);
    }

    if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
        /* 970 gets a U3 bus */
        pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());