diff mbox

[18/21] openpic: add basic support for MPIC v4.2

Message ID 1359118384-9555-19-git-send-email-agraf@suse.de
State New
Headers show

Commit Message

Alexander Graf Jan. 25, 2013, 12:53 p.m. UTC
From: Scott Wood <scottwood@freescale.com>

Besides the new value in the version register, this provides:
- ILR support, which includes:
  - IDR becoming a pure CPU bitmap, allowing 32 CPUs
  - machine check output support (though other parts of QEMU need to
    be fixed for it to do something other than immediately reboot the
    guest)
- dummy error interrupt support (EISR0/EIMR0 read as zero)
  - actually all FSL MPICs get all summary registers returning zero for now,
    which includes EISR0/EIMR0

Various refactoring is done to support these changes and to ease
new functionality (e.g. a more flexible way of declaring regions).

Just as the code was already not a full implementation of MPIC v2.0,
this is not a full implementation of MPIC v4.2 -- e.g. it still has only
one bank of MSIs.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/openpic.c |  338 +++++++++++++++++++++++++++++++++++++++-------------------
 hw/openpic.h |    1 +
 2 files changed, 227 insertions(+), 112 deletions(-)

Comments

Blue Swirl Jan. 25, 2013, 7:23 p.m. UTC | #1
On Fri, Jan 25, 2013 at 12:53 PM, Alexander Graf <agraf@suse.de> wrote:
> From: Scott Wood <scottwood@freescale.com>
>
> Besides the new value in the version register, this provides:
> - ILR support, which includes:
>   - IDR becoming a pure CPU bitmap, allowing 32 CPUs
>   - machine check output support (though other parts of QEMU need to
>     be fixed for it to do something other than immediately reboot the
>     guest)
> - dummy error interrupt support (EISR0/EIMR0 read as zero)
>   - actually all FSL MPICs get all summary registers returning zero for now,
>     which includes EISR0/EIMR0
>
> Various refactoring is done to support these changes and to ease
> new functionality (e.g. a more flexible way of declaring regions).
>
> Just as the code was already not a full implementation of MPIC v2.0,
> this is not a full implementation of MPIC v4.2 -- e.g. it still has only
> one bank of MSIs.
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
>  hw/openpic.c |  338 +++++++++++++++++++++++++++++++++++++++-------------------
>  hw/openpic.h |    1 +
>  2 files changed, 227 insertions(+), 112 deletions(-)
>
> diff --git a/hw/openpic.c b/hw/openpic.c
> index 0a4379f..20a479c 100644
> --- a/hw/openpic.c
> +++ b/hw/openpic.c
> @@ -56,7 +56,7 @@ static const int debug_openpic = 0;
>          } \
>      } while (0)
>
> -#define MAX_CPU     15
> +#define MAX_CPU     32
>  #define MAX_SRC     256
>  #define MAX_TMR     4
>  #define MAX_IPI     4
> @@ -66,6 +66,7 @@ static const int debug_openpic = 0;
>
>  /* OpenPIC capability flags */
>  #define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
> +#define OPENPIC_FLAG_ILR          (2 << 0)
>
>  /* OpenPIC address map */
>  #define OPENPIC_GLB_REG_START        0x0
> @@ -74,6 +75,8 @@ static const int debug_openpic = 0;
>  #define OPENPIC_TMR_REG_SIZE         0x220
>  #define OPENPIC_MSI_REG_START        0x1600
>  #define OPENPIC_MSI_REG_SIZE         0x200
> +#define OPENPIC_SUMMARY_REG_START   0x3800
> +#define OPENPIC_SUMMARY_REG_SIZE    0x800
>  #define OPENPIC_SRC_REG_START        0x10000
>  #define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
>  #define OPENPIC_CPU_REG_START        0x20000
> @@ -94,33 +97,17 @@ static const int debug_openpic = 0;
>  /* 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
> +typedef struct FslMpicInfo {
> +    int max_ext;
> +} FslMpicInfo;
>
> -/* Interrupt definitions */
> -/* IRQs, accessible through the IRQ region */
> -#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 FSL_MPIC_20_TMR_IRQ      0x100
> -#define FSL_MPIC_20_IPI_IRQ      0x104
> +static FslMpicInfo fsl_mpic_20 = {
> +    .max_ext = 12,
> +};
>
> -/*
> - * Block Revision Register1 (BRR1): QEMU does not fully emulate
> - * any version on MPIC. So to start with, set the IP version to 0.
> - *
> - * NOTE: This is Freescale MPIC specific register. Keep it here till
> - * this code is refactored for different variants of OPENPIC and MPIC.
> - */
> -#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
> -#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
> -#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
> +static FslMpicInfo fsl_mpic_42 = {
> +    .max_ext = 12,
> +};
>
>  #define FRR_NIRQ_SHIFT    16
>  #define FRR_NCPU_SHIFT     8
> @@ -146,6 +133,49 @@ static const int debug_openpic = 0;
>  #define IDR_P1_SHIFT      1
>  #define IDR_P0_SHIFT      0
>
> +#define ILR_INTTGT_MASK   0x000000ff
> +#define ILR_INTTGT_INT    0x00
> +#define ILR_INTTGT_CINT   0x01 /* critical */
> +#define ILR_INTTGT_MCP    0x02 /* machine check */
> +
> +/* The currently supported INTTGT values happen to be the same as QEMU's
> + * openpic output codes, but don't depend on this.  The output codes
> + * could change (unlikely, but...) or support could be added for
> + * more INTTGT values.
> + */
> +static const int inttgt_output[][2] = {
> +    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
> +    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
> +    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
> +};
> +
> +static int inttgt_to_output(int inttgt)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
> +        if (inttgt_output[i][0] == inttgt) {
> +            return inttgt_output[i][1];
> +        }
> +    }
> +
> +    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);

No objection, but how about converting this to qemu_log(LOG_UNIMP,...) later?

> +    return OPENPIC_OUTPUT_INT;
> +}
> +
> +static int output_to_inttgt(int output)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
> +        if (inttgt_output[i][1] == output) {
> +            return inttgt_output[i][0];
> +        }
> +    }
> +
> +    abort();
> +}
> +
>  #define MSIIR_OFFSET       0x140
>  #define MSIIR_SRS_SHIFT    29
>  #define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
> @@ -230,6 +260,7 @@ typedef struct OpenPICState {
>      MemoryRegion mem;
>
>      /* Behavior control */
> +    FslMpicInfo *fsl;
>      uint32_t model;
>      uint32_t flags;
>      uint32_t nb_irqs;
> @@ -243,7 +274,7 @@ typedef struct OpenPICState {
>      uint32_t mpic_mode_mask;
>
>      /* Sub-regions */
> -    MemoryRegion sub_io_mem[5];
> +    MemoryRegion sub_io_mem[6];
>
>      /* Global registers */
>      uint32_t frr; /* Feature reporting register */
> @@ -558,6 +589,15 @@ static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
>      return opp->src[n_IRQ].idr;
>  }
>
> +static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
> +{
> +    if (opp->flags & OPENPIC_FLAG_ILR) {
> +        return output_to_inttgt(opp->src[n_IRQ].output);
> +    }
> +
> +    return 0xffffffff;
> +}
> +
>  static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
>  {
>      return opp->src[n_IRQ].ivpr;
> @@ -608,6 +648,19 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
>      }
>  }
>
> +static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
> +{
> +    if (opp->flags & OPENPIC_FLAG_ILR) {
> +        IRQSource *src = &opp->src[n_IRQ];
> +
> +        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
> +        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
> +                src->output);
> +
> +        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
> +    }
> +}
> +
>  static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
>  {
>      uint32_t mask;
> @@ -874,17 +927,20 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
>
>      DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
>              __func__, addr, val);
> -    if (addr & 0xF) {
> -        return;
> -    }
> -    addr = addr & 0xFFF0;
> +
> +    addr = addr & 0xffff;
>      idx = addr >> 5;
> -    if (addr & 0x10) {
> -        /* EXDE / IFEDE / IEEDE */
> -        write_IRQreg_idr(opp, idx, val);
> -    } else {
> -        /* EXVP / IFEVP / IEEVP */
> +
> +    switch (addr & 0x1f) {
> +    case 0x00:
>          write_IRQreg_ivpr(opp, idx, val);
> +        break;
> +    case 0x10:
> +        write_IRQreg_idr(opp, idx, val);
> +        break;
> +    case 0x18:
> +        write_IRQreg_ilr(opp, idx, val);
> +        break;
>      }
>  }
>
> @@ -896,20 +952,23 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
>
>      DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
>      retval = 0xFFFFFFFF;
> -    if (addr & 0xF) {
> -        return retval;
> -    }
> -    addr = addr & 0xFFF0;
> +
> +    addr = addr & 0xffff;
>      idx = addr >> 5;
> -    if (addr & 0x10) {
> -        /* EXDE / IFEDE / IEEDE */
> -        retval = read_IRQreg_idr(opp, idx);
> -    } else {
> -        /* EXVP / IFEVP / IEEVP */
> +
> +    switch (addr & 0x1f) {
> +    case 0x00:
>          retval = read_IRQreg_ivpr(opp, idx);
> +        break;
> +    case 0x10:
> +        retval = read_IRQreg_idr(opp, idx);
> +        break;
> +    case 0x18:
> +        retval = read_IRQreg_ilr(opp, idx);
> +        break;
>      }
> -    DPRINTF("%s: => 0x%08x\n", __func__, retval);
>
> +    DPRINTF("%s: => 0x%08x\n", __func__, retval);
>      return retval;
>  }
>
> @@ -977,6 +1036,26 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
>      return r;
>  }
>
> +static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    uint64_t r = 0;
> +
> +    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
> +
> +    /* TODO: EISR/EIMR */
> +
> +    return r;
> +}
> +
> +static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
> +                                  unsigned size)
> +{
> +    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
> +            __func__, addr, val);
> +
> +    /* TODO: EISR/EIMR */
> +}
> +
>  static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
>                                         uint32_t val, int idx)
>  {
> @@ -1242,19 +1321,19 @@ static const MemoryRegionOps openpic_src_ops_be = {
>      },
>  };
>
> -static const MemoryRegionOps openpic_msi_ops_le = {
> +static const MemoryRegionOps openpic_msi_ops_be = {
>      .read = openpic_msi_read,
>      .write = openpic_msi_write,
> -    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .endianness = DEVICE_BIG_ENDIAN,
>      .impl = {
>          .min_access_size = 4,
>          .max_access_size = 4,
>      },
>  };
>
> -static const MemoryRegionOps openpic_msi_ops_be = {
> -    .read = openpic_msi_read,
> -    .write = openpic_msi_write,
> +static const MemoryRegionOps openpic_summary_ops_be = {
> +    .read = openpic_summary_read,
> +    .write = openpic_summary_write,
>      .endianness = DEVICE_BIG_ENDIAN,
>      .impl = {
>          .min_access_size = 4,
> @@ -1387,78 +1466,128 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id)
>  typedef struct MemReg {
>      const char             *name;
>      MemoryRegionOps const  *ops;
> -    bool                   map;
>      hwaddr      start_addr;
>      ram_addr_t              size;
>  } MemReg;
>
> +static void fsl_common_init(OpenPICState *opp)
> +{
> +    int i;
> +    int virq = MAX_SRC;
> +
> +    opp->vid = VID_REVISION_1_2;
> +    opp->vir = VIR_GENERIC;
> +    opp->vector_mask = 0xFFFF;
> +    opp->tfrr_reset = 0;
> +    opp->ivpr_reset = IVPR_MASK_MASK;
> +    opp->idr_reset = 1 << 0;
> +    opp->max_irq = MAX_IRQ;
> +
> +    opp->irq_ipi0 = virq;
> +    virq += MAX_IPI;
> +    opp->irq_tim0 = virq;
> +    virq += MAX_TMR;
> +
> +    assert(virq <= MAX_IRQ);
> +
> +    opp->irq_msi = 224;
> +
> +    msi_supported = true;
> +    for (i = 0; i < opp->fsl->max_ext; i++) {
> +        opp->src[i].level = false;
> +    }
> +
> +    /* Internal interrupts, including message and MSI */
> +    for (i = 16; i < MAX_SRC; i++) {
> +        opp->src[i].type = IRQ_TYPE_FSLINT;
> +        opp->src[i].level = true;
> +    }
> +
> +    /* timers and IPIs */
> +    for (i = MAX_SRC; i < virq; i++) {
> +        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
> +        opp->src[i].level = false;
> +    }
> +}
> +
> +static void map_list(OpenPICState *opp, const MemReg *list, int *count)
> +{
> +    while (list->name) {
> +        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
> +
> +        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
> +                              list->name, list->size);
> +
> +        memory_region_add_subregion(&opp->mem, list->start_addr,
> +                                    &opp->sub_io_mem[*count]);
> +
> +        (*count)++;
> +        list++;
> +    }
> +}
> +
>  static int openpic_init(SysBusDevice *dev)
>  {
>      OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
>      int i, j;
> -    MemReg list_le[] = {
> -        {"glb", &openpic_glb_ops_le, true,
> +    int list_count = 0;
> +    static const MemReg list_le[] = {
> +        {"glb", &openpic_glb_ops_le,
>                  OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
> -        {"tmr", &openpic_tmr_ops_le, true,
> +        {"tmr", &openpic_tmr_ops_le,
>                  OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
> -        {"msi", &openpic_msi_ops_le, true,
> -                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
> -        {"src", &openpic_src_ops_le, true,
> +        {"src", &openpic_src_ops_le,
>                  OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
> -        {"cpu", &openpic_cpu_ops_le, true,
> +        {"cpu", &openpic_cpu_ops_le,
>                  OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
> +        {NULL}
>      };
> -    MemReg list_be[] = {
> -        {"glb", &openpic_glb_ops_be, true,
> +    static const MemReg list_be[] = {
> +        {"glb", &openpic_glb_ops_be,
>                  OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
> -        {"tmr", &openpic_tmr_ops_be, true,
> +        {"tmr", &openpic_tmr_ops_be,
>                  OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
> -        {"msi", &openpic_msi_ops_be, true,
> -                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
> -        {"src", &openpic_src_ops_be, true,
> +        {"src", &openpic_src_ops_be,
>                  OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
> -        {"cpu", &openpic_cpu_ops_be, true,
> +        {"cpu", &openpic_cpu_ops_be,
>                  OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
> +        {NULL}
>      };
> -    MemReg *list;
> +    static const MemReg list_fsl[] = {
> +        {"msi", &openpic_msi_ops_be,
> +                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
> +        {"summary", &openpic_summary_ops_be,
> +                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
> +        {NULL}
> +    };
> +
> +    memory_region_init(&opp->mem, "openpic", 0x40000);
>
>      switch (opp->model) {
>      case OPENPIC_MODEL_FSL_MPIC_20:
>      default:
> +        opp->fsl = &fsl_mpic_20;
> +        opp->brr1 = 0x00400200;
>          opp->flags |= OPENPIC_FLAG_IDR_CRIT;
>          opp->nb_irqs = 80;
> -        opp->vid = VID_REVISION_1_2;
> -        opp->vir = VIR_GENERIC;
> -        opp->vector_mask = 0xFFFF;
> -        opp->tfrr_reset = 0;
> -        opp->ivpr_reset = IVPR_MASK_MASK;
> -        opp->idr_reset = 1 << 0;
> -        opp->max_irq = FSL_MPIC_20_MAX_IRQ;
> -        opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ;
> -        opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ;
> -        opp->irq_msi = FSL_MPIC_20_MSI_IRQ;
> -        opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
> -        /* XXX really only available as of MPIC 4.0 */
> -        opp->mpic_mode_mask = GCR_MODE_PROXY;
> +        opp->mpic_mode_mask = GCR_MODE_MIXED;
>
> -        msi_supported = true;
> -        list = list_be;
> +        fsl_common_init(opp);
> +        map_list(opp, list_be, &list_count);
> +        map_list(opp, list_fsl, &list_count);
>
> -        for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) {
> -            opp->src[i].level = false;
> -        }
> +        break;
>
> -        /* Internal interrupts, including message and MSI */
> -        for (i = 16; i < MAX_SRC; i++) {
> -            opp->src[i].type = IRQ_TYPE_FSLINT;
> -            opp->src[i].level = true;
> -        }
> +    case OPENPIC_MODEL_FSL_MPIC_42:
> +        opp->fsl = &fsl_mpic_42;
> +        opp->brr1 = 0x00400402;
> +        opp->flags |= OPENPIC_FLAG_ILR;
> +        opp->nb_irqs = 196;
> +        opp->mpic_mode_mask = GCR_MODE_PROXY;
>
> -        /* timers and IPIs */
> -        for (i = MAX_SRC; i < MAX_IRQ; i++) {
> -            opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
> -            opp->src[i].level = false;
> -        }
> +        fsl_common_init(opp);
> +        map_list(opp, list_be, &list_count);
> +        map_list(opp, list_fsl, &list_count);
>
>          break;
>
> @@ -1475,29 +1604,14 @@ static int openpic_init(SysBusDevice *dev)
>          opp->irq_tim0 = RAVEN_TMR_IRQ;
>          opp->brr1 = -1;
>          opp->mpic_mode_mask = GCR_MODE_MIXED;
> -        list = list_le;
> -        /* Don't map MSI region */
> -        list[2].map = false;
>
>          /* 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_le); i++) {
> -        if (!list[i].map) {
> -            continue;
> -        }
> -
> -        memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp,
> -                              list[i].name, list[i].size);
> -
> -        memory_region_add_subregion(&opp->mem, list[i].start_addr,
> -                                    &opp->sub_io_mem[i]);
> +        map_list(opp, list_le, &list_count);
> +        break;
>      }
>
>      for (i = 0; i < opp->nb_cpus; i++) {
> diff --git a/hw/openpic.h b/hw/openpic.h
> index e226d7b..9dcaf0e 100644
> --- a/hw/openpic.h
> +++ b/hw/openpic.h
> @@ -13,5 +13,6 @@ enum {
>
>  #define OPENPIC_MODEL_RAVEN       0
>  #define OPENPIC_MODEL_FSL_MPIC_20 1
> +#define OPENPIC_MODEL_FSL_MPIC_42 2
>
>  #endif /* __OPENPIC_H__ */
> --
> 1.6.0.2
>
Scott Wood Jan. 25, 2013, 7:28 p.m. UTC | #2
On 01/25/2013 01:23:52 PM, Blue Swirl wrote:
> On Fri, Jan 25, 2013 at 12:53 PM, Alexander Graf <agraf@suse.de>  
> wrote:
> > +
> > +static int inttgt_to_output(int inttgt)
> > +{
> > +    int i;
> > +
> > +    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
> > +        if (inttgt_output[i][0] == inttgt) {
> > +            return inttgt_output[i][1];
> > +        }
> > +    }
> > +
> > +    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__,  
> inttgt);
> 
> No objection, but how about converting this to  
> qemu_log(LOG_UNIMP,...) later?

OK, didn't know that existed.

-Scott
Alexander Graf Jan. 25, 2013, 7:33 p.m. UTC | #3
On 25.01.2013, at 20:28, Scott Wood wrote:

> On 01/25/2013 01:23:52 PM, Blue Swirl wrote:
>> On Fri, Jan 25, 2013 at 12:53 PM, Alexander Graf <agraf@suse.de> wrote:
>> > +
>> > +static int inttgt_to_output(int inttgt)
>> > +{
>> > +    int i;
>> > +
>> > +    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
>> > +        if (inttgt_output[i][0] == inttgt) {
>> > +            return inttgt_output[i][1];
>> > +        }
>> > +    }
>> > +
>> > +    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
>> No objection, but how about converting this to qemu_log(LOG_UNIMP,...) later?
> 
> OK, didn't know that existed.

And there I thought qemu_log as only meant for -d (TCG - aka CPU emulation) :).


Alex
diff mbox

Patch

diff --git a/hw/openpic.c b/hw/openpic.c
index 0a4379f..20a479c 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -56,7 +56,7 @@  static const int debug_openpic = 0;
         } \
     } while (0)
 
-#define MAX_CPU     15
+#define MAX_CPU     32
 #define MAX_SRC     256
 #define MAX_TMR     4
 #define MAX_IPI     4
@@ -66,6 +66,7 @@  static const int debug_openpic = 0;
 
 /* OpenPIC capability flags */
 #define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
+#define OPENPIC_FLAG_ILR          (2 << 0)
 
 /* OpenPIC address map */
 #define OPENPIC_GLB_REG_START        0x0
@@ -74,6 +75,8 @@  static const int debug_openpic = 0;
 #define OPENPIC_TMR_REG_SIZE         0x220
 #define OPENPIC_MSI_REG_START        0x1600
 #define OPENPIC_MSI_REG_SIZE         0x200
+#define OPENPIC_SUMMARY_REG_START   0x3800
+#define OPENPIC_SUMMARY_REG_SIZE    0x800
 #define OPENPIC_SRC_REG_START        0x10000
 #define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
 #define OPENPIC_CPU_REG_START        0x20000
@@ -94,33 +97,17 @@  static const int debug_openpic = 0;
 /* 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
+typedef struct FslMpicInfo {
+    int max_ext;
+} FslMpicInfo;
 
-/* Interrupt definitions */
-/* IRQs, accessible through the IRQ region */
-#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 FSL_MPIC_20_TMR_IRQ      0x100
-#define FSL_MPIC_20_IPI_IRQ      0x104
+static FslMpicInfo fsl_mpic_20 = {
+    .max_ext = 12,
+};
 
-/*
- * Block Revision Register1 (BRR1): QEMU does not fully emulate
- * any version on MPIC. So to start with, set the IP version to 0.
- *
- * NOTE: This is Freescale MPIC specific register. Keep it here till
- * this code is refactored for different variants of OPENPIC and MPIC.
- */
-#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
-#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
-#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
+static FslMpicInfo fsl_mpic_42 = {
+    .max_ext = 12,
+};
 
 #define FRR_NIRQ_SHIFT    16
 #define FRR_NCPU_SHIFT     8
@@ -146,6 +133,49 @@  static const int debug_openpic = 0;
 #define IDR_P1_SHIFT      1
 #define IDR_P0_SHIFT      0
 
+#define ILR_INTTGT_MASK   0x000000ff
+#define ILR_INTTGT_INT    0x00
+#define ILR_INTTGT_CINT   0x01 /* critical */
+#define ILR_INTTGT_MCP    0x02 /* machine check */
+
+/* The currently supported INTTGT values happen to be the same as QEMU's
+ * openpic output codes, but don't depend on this.  The output codes
+ * could change (unlikely, but...) or support could be added for
+ * more INTTGT values.
+ */
+static const int inttgt_output[][2] = {
+    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
+    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
+    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
+};
+
+static int inttgt_to_output(int inttgt)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][0] == inttgt) {
+            return inttgt_output[i][1];
+        }
+    }
+
+    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+    return OPENPIC_OUTPUT_INT;
+}
+
+static int output_to_inttgt(int output)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][1] == output) {
+            return inttgt_output[i][0];
+        }
+    }
+
+    abort();
+}
+
 #define MSIIR_OFFSET       0x140
 #define MSIIR_SRS_SHIFT    29
 #define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
@@ -230,6 +260,7 @@  typedef struct OpenPICState {
     MemoryRegion mem;
 
     /* Behavior control */
+    FslMpicInfo *fsl;
     uint32_t model;
     uint32_t flags;
     uint32_t nb_irqs;
@@ -243,7 +274,7 @@  typedef struct OpenPICState {
     uint32_t mpic_mode_mask;
 
     /* Sub-regions */
-    MemoryRegion sub_io_mem[5];
+    MemoryRegion sub_io_mem[6];
 
     /* Global registers */
     uint32_t frr; /* Feature reporting register */
@@ -558,6 +589,15 @@  static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
     return opp->src[n_IRQ].idr;
 }
 
+static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        return output_to_inttgt(opp->src[n_IRQ].output);
+    }
+
+    return 0xffffffff;
+}
+
 static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
 {
     return opp->src[n_IRQ].ivpr;
@@ -608,6 +648,19 @@  static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
     }
 }
 
+static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        IRQSource *src = &opp->src[n_IRQ];
+
+        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
+        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
+                src->output);
+
+        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
+    }
+}
+
 static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
 {
     uint32_t mask;
@@ -874,17 +927,20 @@  static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
 
     DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
             __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-    addr = addr & 0xFFF0;
+
+    addr = addr & 0xffff;
     idx = addr >> 5;
-    if (addr & 0x10) {
-        /* EXDE / IFEDE / IEEDE */
-        write_IRQreg_idr(opp, idx, val);
-    } else {
-        /* EXVP / IFEVP / IEEVP */
+
+    switch (addr & 0x1f) {
+    case 0x00:
         write_IRQreg_ivpr(opp, idx, val);
+        break;
+    case 0x10:
+        write_IRQreg_idr(opp, idx, val);
+        break;
+    case 0x18:
+        write_IRQreg_ilr(opp, idx, val);
+        break;
     }
 }
 
@@ -896,20 +952,23 @@  static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
 
     DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
     retval = 0xFFFFFFFF;
-    if (addr & 0xF) {
-        return retval;
-    }
-    addr = addr & 0xFFF0;
+
+    addr = addr & 0xffff;
     idx = addr >> 5;
-    if (addr & 0x10) {
-        /* EXDE / IFEDE / IEEDE */
-        retval = read_IRQreg_idr(opp, idx);
-    } else {
-        /* EXVP / IFEVP / IEEVP */
+
+    switch (addr & 0x1f) {
+    case 0x00:
         retval = read_IRQreg_ivpr(opp, idx);
+        break;
+    case 0x10:
+        retval = read_IRQreg_idr(opp, idx);
+        break;
+    case 0x18:
+        retval = read_IRQreg_ilr(opp, idx);
+        break;
     }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
 
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
     return retval;
 }
 
@@ -977,6 +1036,26 @@  static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
     return r;
 }
 
+static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t r = 0;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+
+    /* TODO: EISR/EIMR */
+
+    return r;
+}
+
+static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+            __func__, addr, val);
+
+    /* TODO: EISR/EIMR */
+}
+
 static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
                                        uint32_t val, int idx)
 {
@@ -1242,19 +1321,19 @@  static const MemoryRegionOps openpic_src_ops_be = {
     },
 };
 
-static const MemoryRegionOps openpic_msi_ops_le = {
+static const MemoryRegionOps openpic_msi_ops_be = {
     .read = openpic_msi_read,
     .write = openpic_msi_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
+    .endianness = DEVICE_BIG_ENDIAN,
     .impl = {
         .min_access_size = 4,
         .max_access_size = 4,
     },
 };
 
-static const MemoryRegionOps openpic_msi_ops_be = {
-    .read = openpic_msi_read,
-    .write = openpic_msi_write,
+static const MemoryRegionOps openpic_summary_ops_be = {
+    .read = openpic_summary_read,
+    .write = openpic_summary_write,
     .endianness = DEVICE_BIG_ENDIAN,
     .impl = {
         .min_access_size = 4,
@@ -1387,78 +1466,128 @@  static int openpic_load(QEMUFile* f, void *opaque, int version_id)
 typedef struct MemReg {
     const char             *name;
     MemoryRegionOps const  *ops;
-    bool                   map;
     hwaddr      start_addr;
     ram_addr_t              size;
 } MemReg;
 
+static void fsl_common_init(OpenPICState *opp)
+{
+    int i;
+    int virq = MAX_SRC;
+
+    opp->vid = VID_REVISION_1_2;
+    opp->vir = VIR_GENERIC;
+    opp->vector_mask = 0xFFFF;
+    opp->tfrr_reset = 0;
+    opp->ivpr_reset = IVPR_MASK_MASK;
+    opp->idr_reset = 1 << 0;
+    opp->max_irq = MAX_IRQ;
+
+    opp->irq_ipi0 = virq;
+    virq += MAX_IPI;
+    opp->irq_tim0 = virq;
+    virq += MAX_TMR;
+
+    assert(virq <= MAX_IRQ);
+
+    opp->irq_msi = 224;
+
+    msi_supported = true;
+    for (i = 0; i < opp->fsl->max_ext; i++) {
+        opp->src[i].level = false;
+    }
+
+    /* Internal interrupts, including message and MSI */
+    for (i = 16; i < MAX_SRC; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLINT;
+        opp->src[i].level = true;
+    }
+
+    /* timers and IPIs */
+    for (i = MAX_SRC; i < virq; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
+        opp->src[i].level = false;
+    }
+}
+
+static void map_list(OpenPICState *opp, const MemReg *list, int *count)
+{
+    while (list->name) {
+        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
+
+        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
+                              list->name, list->size);
+
+        memory_region_add_subregion(&opp->mem, list->start_addr,
+                                    &opp->sub_io_mem[*count]);
+
+        (*count)++;
+        list++;
+    }
+}
+
 static int openpic_init(SysBusDevice *dev)
 {
     OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
     int i, j;
-    MemReg list_le[] = {
-        {"glb", &openpic_glb_ops_le, true,
+    int list_count = 0;
+    static const MemReg list_le[] = {
+        {"glb", &openpic_glb_ops_le,
                 OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_le, true,
+        {"tmr", &openpic_tmr_ops_le,
                 OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"msi", &openpic_msi_ops_le, true,
-                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
-        {"src", &openpic_src_ops_le, true,
+        {"src", &openpic_src_ops_le,
                 OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_le, true,
+        {"cpu", &openpic_cpu_ops_le,
                 OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
     };
-    MemReg list_be[] = {
-        {"glb", &openpic_glb_ops_be, true,
+    static const MemReg list_be[] = {
+        {"glb", &openpic_glb_ops_be,
                 OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_be, true,
+        {"tmr", &openpic_tmr_ops_be,
                 OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"msi", &openpic_msi_ops_be, true,
-                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
-        {"src", &openpic_src_ops_be, true,
+        {"src", &openpic_src_ops_be,
                 OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_be, true,
+        {"cpu", &openpic_cpu_ops_be,
                 OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
     };
-    MemReg *list;
+    static const MemReg list_fsl[] = {
+        {"msi", &openpic_msi_ops_be,
+                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
+        {"summary", &openpic_summary_ops_be,
+                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
+        {NULL}
+    };
+
+    memory_region_init(&opp->mem, "openpic", 0x40000);
 
     switch (opp->model) {
     case OPENPIC_MODEL_FSL_MPIC_20:
     default:
+        opp->fsl = &fsl_mpic_20;
+        opp->brr1 = 0x00400200;
         opp->flags |= OPENPIC_FLAG_IDR_CRIT;
         opp->nb_irqs = 80;
-        opp->vid = VID_REVISION_1_2;
-        opp->vir = VIR_GENERIC;
-        opp->vector_mask = 0xFFFF;
-        opp->tfrr_reset = 0;
-        opp->ivpr_reset = IVPR_MASK_MASK;
-        opp->idr_reset = 1 << 0;
-        opp->max_irq = FSL_MPIC_20_MAX_IRQ;
-        opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ;
-        opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ;
-        opp->irq_msi = FSL_MPIC_20_MSI_IRQ;
-        opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
-        /* XXX really only available as of MPIC 4.0 */
-        opp->mpic_mode_mask = GCR_MODE_PROXY;
+        opp->mpic_mode_mask = GCR_MODE_MIXED;
 
-        msi_supported = true;
-        list = list_be;
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
 
-        for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) {
-            opp->src[i].level = false;
-        }
+        break;
 
-        /* Internal interrupts, including message and MSI */
-        for (i = 16; i < MAX_SRC; i++) {
-            opp->src[i].type = IRQ_TYPE_FSLINT;
-            opp->src[i].level = true;
-        }
+    case OPENPIC_MODEL_FSL_MPIC_42:
+        opp->fsl = &fsl_mpic_42;
+        opp->brr1 = 0x00400402;
+        opp->flags |= OPENPIC_FLAG_ILR;
+        opp->nb_irqs = 196;
+        opp->mpic_mode_mask = GCR_MODE_PROXY;
 
-        /* timers and IPIs */
-        for (i = MAX_SRC; i < MAX_IRQ; i++) {
-            opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
-            opp->src[i].level = false;
-        }
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
 
         break;
 
@@ -1475,29 +1604,14 @@  static int openpic_init(SysBusDevice *dev)
         opp->irq_tim0 = RAVEN_TMR_IRQ;
         opp->brr1 = -1;
         opp->mpic_mode_mask = GCR_MODE_MIXED;
-        list = list_le;
-        /* Don't map MSI region */
-        list[2].map = false;
 
         /* 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_le); i++) {
-        if (!list[i].map) {
-            continue;
-        }
-
-        memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp,
-                              list[i].name, list[i].size);
-
-        memory_region_add_subregion(&opp->mem, list[i].start_addr,
-                                    &opp->sub_io_mem[i]);
+        map_list(opp, list_le, &list_count);
+        break;
     }
 
     for (i = 0; i < opp->nb_cpus; i++) {
diff --git a/hw/openpic.h b/hw/openpic.h
index e226d7b..9dcaf0e 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -13,5 +13,6 @@  enum {
 
 #define OPENPIC_MODEL_RAVEN       0
 #define OPENPIC_MODEL_FSL_MPIC_20 1
+#define OPENPIC_MODEL_FSL_MPIC_42 2
 
 #endif /* __OPENPIC_H__ */