[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
>
- [Qemu-devel] [PATCH 08/21] ide/macio: QOM'ify MacIO IDE, (continued)
- [Qemu-devel] [PATCH 08/21] ide/macio: QOM'ify MacIO IDE, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 04/21] macio: Split MacIO in two, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 07/21] mac_nvram: QOM'ify MacIO NVRAM, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 12/21] cuda: Move ADB bus into CUDA state, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 05/21] mac_nvram: Clean up public API, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 11/21] adb: QOM'ify ADB devices, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 15/21] pseries: Adjust default VIO address allocations to play better with libvirt, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 13/21] target-ppc: Give a meaningful error if too many threads are specified, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 10/21] adb: QOM'ify Apple Desktop Bus, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 18/21] openpic: add basic support for MPIC v4.2, Alexander Graf, 2013/01/25
- Re: [Qemu-devel] [PATCH 18/21] openpic: add basic support for MPIC v4.2,
Blue Swirl <=
- [Qemu-devel] [PATCH 20/21] PPC: e500: Select MPIC v4.2 on ppce500 platform, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 14/21] pseries: Improve handling of multiple PCI host bridges, Alexander Graf, 2013/01/25
- Re: [Qemu-devel] [PULL 00/21] ppc patch queue 2013-01-25, Andreas Färber, 2013/01/25
- [Qemu-devel] [PATCH 21/21] PPC: Move ppc specific hw emulation to hw/ppc, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 19/21] PPC: e500: fix mpic_iack address, Alexander Graf, 2013/01/25
- [Qemu-devel] [PATCH 17/21] openpic: fix timer address decoding, Alexander Graf, 2013/01/25