qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH 18/21] openpic: add basic support for MPIC v4.2


From: Blue Swirl
Subject: Re: [Qemu-devel] [PATCH 18/21] openpic: add basic support for MPIC v4.2
Date: Fri, 25 Jan 2013 19:23:52 +0000

On Fri, Jan 25, 2013 at 12:53 PM, Alexander Graf <address@hidden> wrote:
> From: Scott Wood <address@hidden>
>
> 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 <address@hidden>
> Signed-off-by: Alexander Graf <address@hidden>
> ---
>  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
>



reply via email to

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