All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: Shashi Mallela <shashi.mallela@linaro.org>
Cc: peter.maydell@linaro.org, leif@nuviainc.com, rad@semihalf.com,
	qemu-arm@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [PATCH v1 1/8] hw/intc: GICv3 ITS initial framework
Date: Thu, 25 Mar 2021 16:43:24 +0000	[thread overview]
Message-ID: <87r1k3gnk5.fsf@linaro.org> (raw)
In-Reply-To: <20210323041238.133835-2-shashi.mallela@linaro.org>


Shashi Mallela <shashi.mallela@linaro.org> writes:

> Added register definitions relevant to ITS,implemented overall
> ITS device framework with stubs for ITS control and translater
> regions read/write,extended ITS common to handle mmio init between
> existing kvm device and newer qemu device.
>
> Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
> ---
>  hw/intc/arm_gicv3_its.c                | 323 ++++++++++++++++++++
>  hw/intc/arm_gicv3_its_common.c         |  17 +-
>  hw/intc/arm_gicv3_its_kvm.c            |   2 +-
>  hw/intc/gicv3_internal.h               | 173 ++++++++++-
>  hw/intc/meson.build                    |   1 +
>  include/hw/intc/arm_gicv3_its_common.h |  12 +-
>  6 files changed, 520 insertions(+), 8 deletions(-)
>
> diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> new file mode 100644
> index 0000000000..34e49b4d63
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_its.c
> @@ -0,0 +1,323 @@
> +/*
> + * ITS emulation for a GICv3-based system
> + *
> + * Copyright Linaro.org 2021
> + *
> + * Authors:
> + *  Shashi Mallela <shashi.mallela@linaro.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at your
> + * option) any later version.  See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/arm_gicv3_its_common.h"
> +#include "gicv3_internal.h"
> +#include "qom/object.h"
> +
> +typedef struct GICv3ITSClass GICv3ITSClass;
> +/* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
> +DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
> +                     ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
> +
> +struct GICv3ITSClass {
> +    GICv3ITSCommonClass parent_class;
> +    void (*parent_reset)(DeviceState *dev);
> +};
> +
> +static MemTxResult its_trans_writew(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_trans_writel(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
> +                               uint64_t data, unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 2:
> +        result = its_trans_writew(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_trans_writel(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest write at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +    }
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
> +                              uint64_t *data, unsigned size, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: Invalid read from transaction register area at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_writeb(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: unsupported byte write to register at offset "
> +                TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;

unsupported should be LOG_UNIMP which makes it easier to see where QEMU
is missing something vs the guest doing something nuts.

> +}
> +
> +static MemTxResult its_readb(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: unsupported byte read from register at offset "
> +                TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_writew(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: unsupported word write to register at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_readw(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: unsupported word read from register at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}

ditto as above

> +
> +static MemTxResult its_writel(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_readl(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_writell(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_readll(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
> +                              unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 1:
> +        result = its_readb(s, offset, data, attrs);
> +        break;
> +    case 2:
> +        result = its_readw(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_readl(s, offset, data, attrs);
> +        break;
> +    case 8:
> +        result = its_readll(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest read at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +        *data = 0;
> +    }
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
> +                               unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 1:
> +        result = its_writeb(s, offset, data, attrs);
> +        break;
> +    case 2:
> +        result = its_writew(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_writel(s, offset, data, attrs);
> +        break;
> +    case 8:
> +        result = its_writell(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest write at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +    }
> +    return result;
> +}
> +
> +static const MemoryRegionOps gicv3_its_control_ops = {
> +    .read_with_attrs = gicv3_its_read,
> +    .write_with_attrs = gicv3_its_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps gicv3_its_trans_ops = {
> +    .read_with_attrs = gicv3_its_trans_read,
> +    .write_with_attrs = gicv3_its_trans_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
> +{
> +    GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
> +
> +    gicv3_its_init_mmio(s, &gicv3_its_control_ops,
> &gicv3_its_trans_ops);

Ahh I got confused later on because we have two local static structures
for &gicv3_its_trans_ops. Could we give them differentiated names
please?

> +}
> +
> +static void gicv3_its_reset(DeviceState *dev)
> +{
> +    GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
> +    GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
> +
> +    if (s->gicv3->cpu->gicr_typer & GICR_TYPER_PLPIS) {
> +        c->parent_reset(dev);
> +
> +        /* set the ITS default features supported */
> +        s->typer = GITS_TYPER_PHYSICAL | (GITS_TYPER_ITT_ENTRY_SIZE <<
> +                   GITS_TYPER_ITT_ENTRY_OFFSET) | (GITS_TYPER_IDBITS <<
> +                   GITS_TYPER_IDBITS_OFFSET) | GITS_TYPER_DEVBITS |
> +                   GITS_TYPER_CIL | GITS_TYPER_CIDBITS;
> +
> +        /*
> +         * We claim to be an ARM r0p0 with a zero ProductID.
> +         * This is the same as an r0p0 GIC-500.
> +         */
> +        s->iidr = gicv3_iidr();
> +
> +        /* Quiescent bit reset to 1 */
> +        s->ctlr = (1U << 31);

I see s->ctlr is set variously with deposit32, manual shift/mask/or and
here with a hard-coded 1 << 31. We generally prefer symbolic names for
register bits. I suspect it might be worth converting the ctlr symbols
to a set of REG32/FIELD descriptors, i.e.:

REG32(GICD_CTLR,                0x0)
    FIELD(GICD_CTLR, EN_GRP0, 0, 1)
    FIELD(GICD_CTLR, EN_GRP1, 1, 1)
    FIELD(GICD_CTLR, RESET,  31, 1)

which would make it:

  s->ctlr = FIELD_DP32(0, GICD_CTLR, RESET, 1);

or

  s->ctlr = (1U << R_GICD_CTLR_RESET_SHIFT);

if the DP32 seems a little over-kill (but probably not). I see bits of
the GIC code have already been converted.

> +
> +        /*
> +         * setting GITS_BASER0.Type = 0b001 (Device)
> +         *         GITS_BASER1.Type = 0b100 (Collection Table)
> +         *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
> +         *         GITS_BASER<0,1>.Page_Size = 64KB
> +         * and default translation table entry size to 16 bytes
> +         */
> +        s->baser[0] = (GITS_ITT_TYPE_DEVICE << GITS_BASER_TYPE_OFFSET) |
> +                      (GITS_BASER_PAGESIZE_64K << GITS_BASER_PAGESIZE_OFFSET) |
> +                      (GITS_DTE_SIZE << GITS_BASER_ENTRYSIZE_OFFSET);
> +        s->baser[1] = (GITS_ITT_TYPE_COLLECTION << GITS_BASER_TYPE_OFFSET) |
> +                      (GITS_BASER_PAGESIZE_64K << GITS_BASER_PAGESIZE_OFFSET) |
> +                      (GITS_CTE_SIZE << GITS_BASER_ENTRYSIZE_OFFSET);
> +    }
> +}
> +
> +static Property gicv3_its_props[] = {
> +    DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
> +                     GICv3State *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void gicv3_its_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
> +
> +    dc->realize = gicv3_arm_its_realize;
> +    device_class_set_props(dc, gicv3_its_props);
> +    device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
> +}
> +
> +static const TypeInfo gicv3_its_info = {
> +    .name = TYPE_ARM_GICV3_ITS,
> +    .parent = TYPE_ARM_GICV3_ITS_COMMON,
> +    .instance_size = sizeof(GICv3ITSState),
> +    .class_init = gicv3_its_class_init,
> +    .class_size = sizeof(GICv3ITSClass),
> +};
> +
> +static void gicv3_its_register_types(void)
> +{
> +    type_register_static(&gicv3_its_info);
> +}
> +
> +type_init(gicv3_its_register_types)
> diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
> index 66c4c6a188..c18fe23fae 100644
> --- a/hw/intc/arm_gicv3_its_common.c
> +++ b/hw/intc/arm_gicv3_its_common.c
> @@ -55,7 +55,9 @@ static const VMStateDescription vmstate_its = {
>      .priority = MIG_PRI_GICV3_ITS,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINT32(ctlr, GICv3ITSState),
> +        VMSTATE_UINT32(translater, GICv3ITSState),
>          VMSTATE_UINT32(iidr, GICv3ITSState),
> +        VMSTATE_UINT64(typer, GICv3ITSState),
>          VMSTATE_UINT64(cbaser, GICv3ITSState),
>          VMSTATE_UINT64(cwriter, GICv3ITSState),
>          VMSTATE_UINT64(creadr, GICv3ITSState),

I think you need to bump:

    .version_id = 1,
    .minimum_version_id = 1,

here so we don't attempt to migrate in an incompatible VMstate from a
pre-ITS migration. Are these fields always used now? If not we might
want to jump a few more hoops to preserve compatibility and make the
fields optional.

> @@ -99,15 +101,21 @@ static const MemoryRegionOps gicv3_its_trans_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>  
> -void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
> +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
> +     const MemoryRegionOps *tops)
>  {
>      SysBusDevice *sbd = SYS_BUS_DEVICE(s);
>  
>      memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
>                            "control", ITS_CONTROL_SIZE);
> -    memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> -                          &gicv3_its_trans_ops, s,
> -                          "translation", ITS_TRANS_SIZE);
> +    if (tops == NULL) {
> +        memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> +                              &gicv3_its_trans_ops, s,
> +                              "translation", ITS_TRANS_SIZE);
> +    } else {
> +        memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> +                              tops, s, "translation", ITS_TRANS_SIZE);
> +    }

You might as well short-circuit it one line as it's the only difference,
i.e.:

   memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
                         tops ? tops : &gicv3_its_trans_ops, s,
                         "translation", ITS_TRANS_SIZE);

but see bellow.

>      /* Our two regions are always adjacent, therefore we now combine them
>       * into a single one in order to make our users' life easier.
> @@ -130,6 +138,7 @@ static void gicv3_its_common_reset(DeviceState *dev)
>      s->cwriter = 0;
>      s->creadr = 0;
>      s->iidr = 0;
> +    s->translater = 0;
>      memset(&s->baser, 0, sizeof(s->baser));
>  }
>  
> diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
> index b554d2ede0..0b4cbed28b 100644
> --- a/hw/intc/arm_gicv3_its_kvm.c
> +++ b/hw/intc/arm_gicv3_its_kvm.c
> @@ -106,7 +106,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
>      kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
>                              KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0);
>  
> -    gicv3_its_init_mmio(s, NULL);
> +    gicv3_its_init_mmio(s, NULL, NULL);
>  
>      if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
>          GITS_CTLR)) {
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 05303a55c8..7c6bc33e97 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -67,6 +67,12 @@
>  #define GICD_CTLR_E1NWF             (1U << 7)
>  #define GICD_CTLR_RWP               (1U << 31)
>  
> +#define GICD_TYPER_LPIS_OFFSET         17
> +#define GICD_TYPER_IDBITS_OFFSET       19
> +#define GICD_TYPER_IDBITS_MASK       0x1f
> +/* 16 bits EventId */
> +#define GICD_TYPER_IDBITS            0xf
> +
>  /*
>   * Redistributor frame offsets from RD_base
>   */
> @@ -123,14 +129,17 @@
>  #define GICR_WAKER_ChildrenAsleep    (1U << 2)
>  
>  #define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
> -#define GICR_PROPBASER_ADDR_MASK               (0xfffffffffULL << 12)
> +#define GICR_PROPBASER_ADDR_OFFSET               12
> +#define GICR_PROPBASER_ADDR_MASK               ((1ULL << 40) - 1)
>  #define GICR_PROPBASER_SHAREABILITY_MASK       (3U << 10)
>  #define GICR_PROPBASER_CACHEABILITY_MASK       (7U << 7)
>  #define GICR_PROPBASER_IDBITS_MASK             (0x1f)
> +#define GICR_PROPBASER_IDBITS_THRESHOLD          0xd

More candidates for REG/FIELD conversion.

>  
>  #define GICR_PENDBASER_PTZ                     (1ULL << 62)
>  #define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
> -#define GICR_PENDBASER_ADDR_MASK               (0xffffffffULL << 16)
> +#define GICR_PENDBASER_ADDR_OFFSET               16
> +#define GICR_PENDBASER_ADDR_MASK               ((1ULL << 36) - 1)
>  #define GICR_PENDBASER_SHAREABILITY_MASK       (3U << 10)
>  #define GICR_PENDBASER_CACHEABILITY_MASK       (7U << 7)
>  
> @@ -239,11 +248,171 @@
>  #define ICH_VTR_EL2_PREBITS_SHIFT 26
>  #define ICH_VTR_EL2_PRIBITS_SHIFT 29
>  
> +#define GITS_CTLR_ENABLED             (1U << 0)  /* ITS Enabled or not */
> +#define GITS_CTLR_QUIESCENT           (1U << 31) /* Quiescent bit */
> +
> +#define GITS_BASER_SIZE                     (0xff)
> +#define GITS_BASER_PAGESIZE_OFFSET            8
> +#define GITS_BASER_PAGESIZE_MASK             0x3
> +#define GITS_BASER_SHAREABILITY_OFFSET        10
> +#define GITS_BASER_SHAREABILITY_MASK         0x3
> +#define GITS_BASER_PHYADDR_OFFSET             12
> +#define GITS_BASER_PHYADDR_MASK             ((1ULL << 36) - 1)
> +#define GITS_BASER_PHYADDR_OFFSETL_64K        16
> +#define GITS_BASER_PHYADDR_MASKL_64K        ((1ULL << 32) - 1)
> +#define GITS_BASER_PHYADDR_OFFSETH_64K        48
> +#define GITS_BASER_PHYADDR_MASKH_64K        ((1ULL << 4) - 1)
> +#define GITS_BASER_ENTRYSIZE_OFFSET           48
> +#define GITS_BASER_ENTRYSIZE_MASK           ((1U << 5) - 1)
> +#define GITS_BASER_OUTERCACHE_OFFSET          53
> +#define GITS_BASER_OUTERCACHE_MASK            0x7
> +#define GITS_BASER_TYPE_OFFSET                56
> +#define GITS_BASER_TYPE_MASK                  0x7
> +#define GITS_BASER_INNERCACHE_OFFSET          59
> +#define GITS_BASER_INNERCACHE_MASK            0x7
> +#define GITS_BASER_INDIRECT_OFFSET            62
> +#define GITS_BASER_INDIRECT_MASK              0x1
> +#define GITS_BASER_VALID                      63
> +#define GITS_BASER_VALID_MASK                 0x1
> +
> +#define GITS_BASER_VAL_MASK                 ((0x7ULL << 56) | (0x1fULL << 48))
> +
> +#define GITS_BASER_PAGESIZE_4K                0
> +#define GITS_BASER_PAGESIZE_16K               1
> +#define GITS_BASER_PAGESIZE_64K               2
> +
> +#define GITS_ITT_TYPE_DEVICE                  1ULL
> +#define GITS_ITT_TYPE_COLLECTION              4ULL
> +
> +#define GITS_CBASER_SIZE                    (0xff)
> +#define GITS_CBASER_SHAREABILITY_OFFSET       10
> +#define GITS_CBASER_SHAREABILITY_MASK        0x3
> +#define GITS_CBASER_PHYADDR_OFFSET            12
> +#define GITS_CBASER_PHYADDR_MASK       ((1ULL << 40) - 1)
> +#define GITS_CBASER_OUTERCACHE_OFFSET         53
> +#define GITS_CBASER_OUTERCACHE_MASK          0x7
> +#define GITS_CBASER_INNERCACHE_OFFSET         59
> +#define GITS_CBASER_INNERCACHE_MASK          0x7
> +#define GITS_CBASER_VALID_OFFSET              63
> +#define GITS_CBASER_VALID_MASK               0x1
> +
> +#define GITS_CREADR_STALLED           (1U << 0)
> +#define GITS_CREADR_OFFSET             5
> +#define GITS_CREADR_OFFSET_MASK       ((1U << 15) - 1)
> +
> +#define GITS_CWRITER_RETRY            (1U << 0)
> +#define GITS_CWRITER_OFFSET             5
> +#define GITS_CWRITER_OFFSET_MASK      ((1U << 15) - 1)
> +
> +#define GITS_TYPER_DEVBITS_OFFSET       13
> +#define GITS_TYPER_DEVBITS_MASK        0x1f
> +#define GITS_TYPER_IDBITS_OFFSET        8
> +#define GITS_TYPER_IDBITS_MASK         0x1f
> +#define GITS_TYPER_CIDBITS_OFFSET       32
> +#define GITS_TYPER_CIDBITS_MASK        0xf
> +#define GITS_TYPER_CIL_OFFSET           36
> +#define GITS_TYPER_CIL_MASK             0x1
> +#define GITS_TYPER_PTA_OFFSET           19
> +#define GITS_TYPER_PTA_MASK             0x1
> +#define GITS_TYPER_SEIS_OFFSET          18
> +#define GITS_TYPER_SEIS_MASK            0x1

And here.

> +
> +/* Default features advertised by this version of ITS */
> +/* Physical LPIs supported */
> +#define GITS_TYPER_PHYSICAL           (1U << 0)
> +/*
> + * 11 bytes Interrupt translation Table Entry size
> + * Valid = 1 bit,InterruptType = 1 bit,
> + * Size of LPI number space[considering max 24 bits],
> + * Size of LPI number space[considering max 24 bits],
> + * ICID = 16 bits,
> + * vPEID = 16 bits
> + */
> +#define GITS_TYPER_ITT_ENTRY_OFFSET     4
> +#define GITS_TYPER_ITT_ENTRY_SIZE       0xB
> +#define GITS_TYPER_IDBITS_OFFSET        8
> +
> +/* 16 bits EventId */
> +#define GITS_TYPER_IDBITS             GICD_TYPER_IDBITS
> +/* 16 bits DeviceId */
> +#define GITS_TYPER_DEVBITS            (0xf << 13)
> +/* Collection ID Limit indicated by CIDbits(next) */
> +#define GITS_TYPER_CIL                (1ULL << 36)
> +/* 16 bits CollectionId */
> +#define GITS_TYPER_CIDBITS            (0xfULL << 32)
> +/*
> + * 8 bytes Device Table Entry size
> + * Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits
> + */
> +#define GITS_DTE_SIZE                 (0x8ULL)
> +/*
> + * 8 bytes Collection Table Entry size
> + * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
> + */
> +#define GITS_CTE_SIZE                 (0x8ULL)
> +
>  /* Special interrupt IDs */
>  #define INTID_SECURE 1020
>  #define INTID_NONSECURE 1021
>  #define INTID_SPURIOUS 1023
>  
> +/* ITS Commands */
> +#define GITS_CMD_CLEAR            0x04
> +#define GITS_CMD_DISCARD          0x0F
> +#define GITS_CMD_INT              0x03
> +#define GITS_CMD_MAPC             0x09
> +#define GITS_CMD_MAPD             0x08
> +#define GITS_CMD_MAPI             0x0B
> +#define GITS_CMD_MAPTI            0x0A
> +#define GITS_CMD_SYNC             0x05

Although looking at this patch I suspect the definition of registers
should come in when they are first used.

> +
> +#define GITS_ITT_PAGE_SIZE_0      0x1000
> +#define GITS_ITT_PAGE_SIZE_1      0x4000
> +#define GITS_ITT_PAGE_SIZE_2      0x10000
> +
> +#define GITS_CMDQ_ENTRY_SIZE               32
> +#define GITS_CMDQ_MAX_ENTRIES_PER_PAGE     128
> +#define NUM_BYTES_IN_DW                     8
> +
> +#define CMD_MASK                  0xff
> +
> +/* MAPC command fields */
> +#define ICID_LEN                  16
> +#define ICID_MASK                 ((1U << ICID_LEN) - 1)
> +#define RDBASE_LEN                32
> +#define RDBASE_OFFSET             16
> +#define RDBASE_MASK               ((1ULL << RDBASE_LEN) - 1)
> +#define RDBASE_PROCNUM_LEN        16
> +#define RDBASE_PROCNUM_MASK       ((1ULL << RDBASE_PROCNUM_LEN) - 1)
> +
> +#define DEVID_OFFSET              32
> +#define DEVID_LEN                 32
> +#define DEVID_MASK                ((1ULL << DEVID_LEN) - 1)
> +
> +/* MAPD command fields */
> +#define ITTADDR_LEN               44
> +#define ITTADDR_OFFSET            8
> +#define ITTADDR_MASK              ((1ULL << ITTADDR_LEN) - 1)
> +#define SIZE_MASK                 0x1f
> +
> +/* MAPI command fields */
> +#define EVENTID_MASK              ((1ULL << 32) - 1)
> +
> +/* MAPTI command fields */
> +#define pINTID_OFFSET              32
> +#define pINTID_MASK               ((1ULL << 32) - 1)
> +
> +#define VALID_SHIFT               63
> +#define VALID_MASK                0x1
> +
> +#define L1TABLE_ENTRY_SIZE         8
> +
> +#define LPI_CTE_ENABLE_OFFSET      0
> +#define LPI_CTE_ENABLED          VALID_MASK
> +#define LPI_CTE_PRIORITY_OFFSET    2
> +#define LPI_CTE_PRIORITY_MASK     ((1U << 6) - 1)
> +#define LPI_PRIORITY_MASK         0xfc
> +
>  /* Functions internal to the emulated GICv3 */
>  
>  /**
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..53472239f0 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -8,6 +8,7 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
>    'arm_gicv3_dist.c',
>    'arm_gicv3_its_common.c',
>    'arm_gicv3_redist.c',
> +  'arm_gicv3_its.c',
>  ))
>  softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
>  softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
> diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
> index 5a0952b404..08bc5652ed 100644
> --- a/include/hw/intc/arm_gicv3_its_common.h
> +++ b/include/hw/intc/arm_gicv3_its_common.h
> @@ -25,17 +25,24 @@
>  #include "hw/intc/arm_gicv3_common.h"
>  #include "qom/object.h"
>  
> +#define TYPE_ARM_GICV3_ITS "arm-gicv3-its"
> +
>  #define ITS_CONTROL_SIZE 0x10000
>  #define ITS_TRANS_SIZE   0x10000
>  #define ITS_SIZE         (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
>  
>  #define GITS_CTLR        0x0
>  #define GITS_IIDR        0x4
> +#define GITS_TYPER       0x8
>  #define GITS_CBASER      0x80
>  #define GITS_CWRITER     0x88
>  #define GITS_CREADR      0x90
>  #define GITS_BASER       0x100
>  
> +#define GITS_TRANSLATER  0x0040
> +
> +#define GITS_PIDR2       0xFFE8
> +
>  struct GICv3ITSState {
>      SysBusDevice parent_obj;
>  
> @@ -52,6 +59,8 @@ struct GICv3ITSState {
>      /* Registers */
>      uint32_t ctlr;
>      uint32_t iidr;
> +    uint32_t translater;
> +    uint64_t typer;
>      uint64_t cbaser;
>      uint64_t cwriter;
>      uint64_t creadr;
> @@ -62,7 +71,8 @@ struct GICv3ITSState {
>  
>  typedef struct GICv3ITSState GICv3ITSState;
>  
> -void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
> +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
> +                   const MemoryRegionOps *tops);
>  
>  #define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
>  typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;


-- 
Alex Bennée

WARNING: multiple messages have this Message-ID (diff)
From: "Alex Bennée" <alex.bennee@linaro.org>
To: Shashi Mallela <shashi.mallela@linaro.org>
Cc: peter.maydell@linaro.org, leif@nuviainc.com,
	qemu-devel@nongnu.org, qemu-arm@nongnu.org, rad@semihalf.com
Subject: Re: [PATCH v1 1/8] hw/intc: GICv3 ITS initial framework
Date: Thu, 25 Mar 2021 16:43:24 +0000	[thread overview]
Message-ID: <87r1k3gnk5.fsf@linaro.org> (raw)
In-Reply-To: <20210323041238.133835-2-shashi.mallela@linaro.org>


Shashi Mallela <shashi.mallela@linaro.org> writes:

> Added register definitions relevant to ITS,implemented overall
> ITS device framework with stubs for ITS control and translater
> regions read/write,extended ITS common to handle mmio init between
> existing kvm device and newer qemu device.
>
> Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
> ---
>  hw/intc/arm_gicv3_its.c                | 323 ++++++++++++++++++++
>  hw/intc/arm_gicv3_its_common.c         |  17 +-
>  hw/intc/arm_gicv3_its_kvm.c            |   2 +-
>  hw/intc/gicv3_internal.h               | 173 ++++++++++-
>  hw/intc/meson.build                    |   1 +
>  include/hw/intc/arm_gicv3_its_common.h |  12 +-
>  6 files changed, 520 insertions(+), 8 deletions(-)
>
> diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> new file mode 100644
> index 0000000000..34e49b4d63
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_its.c
> @@ -0,0 +1,323 @@
> +/*
> + * ITS emulation for a GICv3-based system
> + *
> + * Copyright Linaro.org 2021
> + *
> + * Authors:
> + *  Shashi Mallela <shashi.mallela@linaro.org>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at your
> + * option) any later version.  See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/arm_gicv3_its_common.h"
> +#include "gicv3_internal.h"
> +#include "qom/object.h"
> +
> +typedef struct GICv3ITSClass GICv3ITSClass;
> +/* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
> +DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
> +                     ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
> +
> +struct GICv3ITSClass {
> +    GICv3ITSCommonClass parent_class;
> +    void (*parent_reset)(DeviceState *dev);
> +};
> +
> +static MemTxResult its_trans_writew(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_trans_writel(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset,
> +                               uint64_t data, unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 2:
> +        result = its_trans_writew(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_trans_writel(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest write at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +    }
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset,
> +                              uint64_t *data, unsigned size, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: Invalid read from transaction register area at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_writeb(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: unsupported byte write to register at offset "
> +                TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;

unsupported should be LOG_UNIMP which makes it easier to see where QEMU
is missing something vs the guest doing something nuts.

> +}
> +
> +static MemTxResult its_readb(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +                "%s: unsupported byte read from register at offset "
> +                TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_writew(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: unsupported word write to register at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}
> +
> +static MemTxResult its_readw(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +        "%s: unsupported word read from register at offset "
> +        TARGET_FMT_plx "\n", __func__, offset);
> +    return MEMTX_ERROR;
> +}

ditto as above

> +
> +static MemTxResult its_writel(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_readl(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_writell(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t value, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult its_readll(GICv3ITSState *s, hwaddr offset,
> +                               uint64_t *data, MemTxAttrs attrs)
> +{
> +    MemTxResult result = MEMTX_OK;
> +
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
> +                              unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 1:
> +        result = its_readb(s, offset, data, attrs);
> +        break;
> +    case 2:
> +        result = its_readw(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_readl(s, offset, data, attrs);
> +        break;
> +    case 8:
> +        result = its_readll(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest read at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +        *data = 0;
> +    }
> +    return result;
> +}
> +
> +static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
> +                               unsigned size, MemTxAttrs attrs)
> +{
> +    GICv3ITSState *s = (GICv3ITSState *)opaque;
> +    MemTxResult result;
> +
> +    switch (size) {
> +    case 1:
> +        result = its_writeb(s, offset, data, attrs);
> +        break;
> +    case 2:
> +        result = its_writew(s, offset, data, attrs);
> +        break;
> +    case 4:
> +        result = its_writel(s, offset, data, attrs);
> +        break;
> +    case 8:
> +        result = its_writell(s, offset, data, attrs);
> +        break;
> +    default:
> +        result = MEMTX_ERROR;
> +        break;
> +    }
> +
> +    if (result == MEMTX_ERROR) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: invalid guest write at offset " TARGET_FMT_plx
> +                      "size %u\n", __func__, offset, size);
> +        /*
> +         * The spec requires that reserved registers are RAZ/WI;
> +         * so use MEMTX_ERROR returns from leaf functions as a way to
> +         * trigger the guest-error logging but don't return it to
> +         * the caller, or we'll cause a spurious guest data abort.
> +         */
> +        result = MEMTX_OK;
> +    }
> +    return result;
> +}
> +
> +static const MemoryRegionOps gicv3_its_control_ops = {
> +    .read_with_attrs = gicv3_its_read,
> +    .write_with_attrs = gicv3_its_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps gicv3_its_trans_ops = {
> +    .read_with_attrs = gicv3_its_trans_read,
> +    .write_with_attrs = gicv3_its_trans_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
> +{
> +    GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
> +
> +    gicv3_its_init_mmio(s, &gicv3_its_control_ops,
> &gicv3_its_trans_ops);

Ahh I got confused later on because we have two local static structures
for &gicv3_its_trans_ops. Could we give them differentiated names
please?

> +}
> +
> +static void gicv3_its_reset(DeviceState *dev)
> +{
> +    GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
> +    GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
> +
> +    if (s->gicv3->cpu->gicr_typer & GICR_TYPER_PLPIS) {
> +        c->parent_reset(dev);
> +
> +        /* set the ITS default features supported */
> +        s->typer = GITS_TYPER_PHYSICAL | (GITS_TYPER_ITT_ENTRY_SIZE <<
> +                   GITS_TYPER_ITT_ENTRY_OFFSET) | (GITS_TYPER_IDBITS <<
> +                   GITS_TYPER_IDBITS_OFFSET) | GITS_TYPER_DEVBITS |
> +                   GITS_TYPER_CIL | GITS_TYPER_CIDBITS;
> +
> +        /*
> +         * We claim to be an ARM r0p0 with a zero ProductID.
> +         * This is the same as an r0p0 GIC-500.
> +         */
> +        s->iidr = gicv3_iidr();
> +
> +        /* Quiescent bit reset to 1 */
> +        s->ctlr = (1U << 31);

I see s->ctlr is set variously with deposit32, manual shift/mask/or and
here with a hard-coded 1 << 31. We generally prefer symbolic names for
register bits. I suspect it might be worth converting the ctlr symbols
to a set of REG32/FIELD descriptors, i.e.:

REG32(GICD_CTLR,                0x0)
    FIELD(GICD_CTLR, EN_GRP0, 0, 1)
    FIELD(GICD_CTLR, EN_GRP1, 1, 1)
    FIELD(GICD_CTLR, RESET,  31, 1)

which would make it:

  s->ctlr = FIELD_DP32(0, GICD_CTLR, RESET, 1);

or

  s->ctlr = (1U << R_GICD_CTLR_RESET_SHIFT);

if the DP32 seems a little over-kill (but probably not). I see bits of
the GIC code have already been converted.

> +
> +        /*
> +         * setting GITS_BASER0.Type = 0b001 (Device)
> +         *         GITS_BASER1.Type = 0b100 (Collection Table)
> +         *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
> +         *         GITS_BASER<0,1>.Page_Size = 64KB
> +         * and default translation table entry size to 16 bytes
> +         */
> +        s->baser[0] = (GITS_ITT_TYPE_DEVICE << GITS_BASER_TYPE_OFFSET) |
> +                      (GITS_BASER_PAGESIZE_64K << GITS_BASER_PAGESIZE_OFFSET) |
> +                      (GITS_DTE_SIZE << GITS_BASER_ENTRYSIZE_OFFSET);
> +        s->baser[1] = (GITS_ITT_TYPE_COLLECTION << GITS_BASER_TYPE_OFFSET) |
> +                      (GITS_BASER_PAGESIZE_64K << GITS_BASER_PAGESIZE_OFFSET) |
> +                      (GITS_CTE_SIZE << GITS_BASER_ENTRYSIZE_OFFSET);
> +    }
> +}
> +
> +static Property gicv3_its_props[] = {
> +    DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
> +                     GICv3State *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void gicv3_its_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
> +
> +    dc->realize = gicv3_arm_its_realize;
> +    device_class_set_props(dc, gicv3_its_props);
> +    device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
> +}
> +
> +static const TypeInfo gicv3_its_info = {
> +    .name = TYPE_ARM_GICV3_ITS,
> +    .parent = TYPE_ARM_GICV3_ITS_COMMON,
> +    .instance_size = sizeof(GICv3ITSState),
> +    .class_init = gicv3_its_class_init,
> +    .class_size = sizeof(GICv3ITSClass),
> +};
> +
> +static void gicv3_its_register_types(void)
> +{
> +    type_register_static(&gicv3_its_info);
> +}
> +
> +type_init(gicv3_its_register_types)
> diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
> index 66c4c6a188..c18fe23fae 100644
> --- a/hw/intc/arm_gicv3_its_common.c
> +++ b/hw/intc/arm_gicv3_its_common.c
> @@ -55,7 +55,9 @@ static const VMStateDescription vmstate_its = {
>      .priority = MIG_PRI_GICV3_ITS,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINT32(ctlr, GICv3ITSState),
> +        VMSTATE_UINT32(translater, GICv3ITSState),
>          VMSTATE_UINT32(iidr, GICv3ITSState),
> +        VMSTATE_UINT64(typer, GICv3ITSState),
>          VMSTATE_UINT64(cbaser, GICv3ITSState),
>          VMSTATE_UINT64(cwriter, GICv3ITSState),
>          VMSTATE_UINT64(creadr, GICv3ITSState),

I think you need to bump:

    .version_id = 1,
    .minimum_version_id = 1,

here so we don't attempt to migrate in an incompatible VMstate from a
pre-ITS migration. Are these fields always used now? If not we might
want to jump a few more hoops to preserve compatibility and make the
fields optional.

> @@ -99,15 +101,21 @@ static const MemoryRegionOps gicv3_its_trans_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>  
> -void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
> +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
> +     const MemoryRegionOps *tops)
>  {
>      SysBusDevice *sbd = SYS_BUS_DEVICE(s);
>  
>      memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
>                            "control", ITS_CONTROL_SIZE);
> -    memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> -                          &gicv3_its_trans_ops, s,
> -                          "translation", ITS_TRANS_SIZE);
> +    if (tops == NULL) {
> +        memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> +                              &gicv3_its_trans_ops, s,
> +                              "translation", ITS_TRANS_SIZE);
> +    } else {
> +        memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
> +                              tops, s, "translation", ITS_TRANS_SIZE);
> +    }

You might as well short-circuit it one line as it's the only difference,
i.e.:

   memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
                         tops ? tops : &gicv3_its_trans_ops, s,
                         "translation", ITS_TRANS_SIZE);

but see bellow.

>      /* Our two regions are always adjacent, therefore we now combine them
>       * into a single one in order to make our users' life easier.
> @@ -130,6 +138,7 @@ static void gicv3_its_common_reset(DeviceState *dev)
>      s->cwriter = 0;
>      s->creadr = 0;
>      s->iidr = 0;
> +    s->translater = 0;
>      memset(&s->baser, 0, sizeof(s->baser));
>  }
>  
> diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
> index b554d2ede0..0b4cbed28b 100644
> --- a/hw/intc/arm_gicv3_its_kvm.c
> +++ b/hw/intc/arm_gicv3_its_kvm.c
> @@ -106,7 +106,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
>      kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
>                              KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0);
>  
> -    gicv3_its_init_mmio(s, NULL);
> +    gicv3_its_init_mmio(s, NULL, NULL);
>  
>      if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
>          GITS_CTLR)) {
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 05303a55c8..7c6bc33e97 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -67,6 +67,12 @@
>  #define GICD_CTLR_E1NWF             (1U << 7)
>  #define GICD_CTLR_RWP               (1U << 31)
>  
> +#define GICD_TYPER_LPIS_OFFSET         17
> +#define GICD_TYPER_IDBITS_OFFSET       19
> +#define GICD_TYPER_IDBITS_MASK       0x1f
> +/* 16 bits EventId */
> +#define GICD_TYPER_IDBITS            0xf
> +
>  /*
>   * Redistributor frame offsets from RD_base
>   */
> @@ -123,14 +129,17 @@
>  #define GICR_WAKER_ChildrenAsleep    (1U << 2)
>  
>  #define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
> -#define GICR_PROPBASER_ADDR_MASK               (0xfffffffffULL << 12)
> +#define GICR_PROPBASER_ADDR_OFFSET               12
> +#define GICR_PROPBASER_ADDR_MASK               ((1ULL << 40) - 1)
>  #define GICR_PROPBASER_SHAREABILITY_MASK       (3U << 10)
>  #define GICR_PROPBASER_CACHEABILITY_MASK       (7U << 7)
>  #define GICR_PROPBASER_IDBITS_MASK             (0x1f)
> +#define GICR_PROPBASER_IDBITS_THRESHOLD          0xd

More candidates for REG/FIELD conversion.

>  
>  #define GICR_PENDBASER_PTZ                     (1ULL << 62)
>  #define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
> -#define GICR_PENDBASER_ADDR_MASK               (0xffffffffULL << 16)
> +#define GICR_PENDBASER_ADDR_OFFSET               16
> +#define GICR_PENDBASER_ADDR_MASK               ((1ULL << 36) - 1)
>  #define GICR_PENDBASER_SHAREABILITY_MASK       (3U << 10)
>  #define GICR_PENDBASER_CACHEABILITY_MASK       (7U << 7)
>  
> @@ -239,11 +248,171 @@
>  #define ICH_VTR_EL2_PREBITS_SHIFT 26
>  #define ICH_VTR_EL2_PRIBITS_SHIFT 29
>  
> +#define GITS_CTLR_ENABLED             (1U << 0)  /* ITS Enabled or not */
> +#define GITS_CTLR_QUIESCENT           (1U << 31) /* Quiescent bit */
> +
> +#define GITS_BASER_SIZE                     (0xff)
> +#define GITS_BASER_PAGESIZE_OFFSET            8
> +#define GITS_BASER_PAGESIZE_MASK             0x3
> +#define GITS_BASER_SHAREABILITY_OFFSET        10
> +#define GITS_BASER_SHAREABILITY_MASK         0x3
> +#define GITS_BASER_PHYADDR_OFFSET             12
> +#define GITS_BASER_PHYADDR_MASK             ((1ULL << 36) - 1)
> +#define GITS_BASER_PHYADDR_OFFSETL_64K        16
> +#define GITS_BASER_PHYADDR_MASKL_64K        ((1ULL << 32) - 1)
> +#define GITS_BASER_PHYADDR_OFFSETH_64K        48
> +#define GITS_BASER_PHYADDR_MASKH_64K        ((1ULL << 4) - 1)
> +#define GITS_BASER_ENTRYSIZE_OFFSET           48
> +#define GITS_BASER_ENTRYSIZE_MASK           ((1U << 5) - 1)
> +#define GITS_BASER_OUTERCACHE_OFFSET          53
> +#define GITS_BASER_OUTERCACHE_MASK            0x7
> +#define GITS_BASER_TYPE_OFFSET                56
> +#define GITS_BASER_TYPE_MASK                  0x7
> +#define GITS_BASER_INNERCACHE_OFFSET          59
> +#define GITS_BASER_INNERCACHE_MASK            0x7
> +#define GITS_BASER_INDIRECT_OFFSET            62
> +#define GITS_BASER_INDIRECT_MASK              0x1
> +#define GITS_BASER_VALID                      63
> +#define GITS_BASER_VALID_MASK                 0x1
> +
> +#define GITS_BASER_VAL_MASK                 ((0x7ULL << 56) | (0x1fULL << 48))
> +
> +#define GITS_BASER_PAGESIZE_4K                0
> +#define GITS_BASER_PAGESIZE_16K               1
> +#define GITS_BASER_PAGESIZE_64K               2
> +
> +#define GITS_ITT_TYPE_DEVICE                  1ULL
> +#define GITS_ITT_TYPE_COLLECTION              4ULL
> +
> +#define GITS_CBASER_SIZE                    (0xff)
> +#define GITS_CBASER_SHAREABILITY_OFFSET       10
> +#define GITS_CBASER_SHAREABILITY_MASK        0x3
> +#define GITS_CBASER_PHYADDR_OFFSET            12
> +#define GITS_CBASER_PHYADDR_MASK       ((1ULL << 40) - 1)
> +#define GITS_CBASER_OUTERCACHE_OFFSET         53
> +#define GITS_CBASER_OUTERCACHE_MASK          0x7
> +#define GITS_CBASER_INNERCACHE_OFFSET         59
> +#define GITS_CBASER_INNERCACHE_MASK          0x7
> +#define GITS_CBASER_VALID_OFFSET              63
> +#define GITS_CBASER_VALID_MASK               0x1
> +
> +#define GITS_CREADR_STALLED           (1U << 0)
> +#define GITS_CREADR_OFFSET             5
> +#define GITS_CREADR_OFFSET_MASK       ((1U << 15) - 1)
> +
> +#define GITS_CWRITER_RETRY            (1U << 0)
> +#define GITS_CWRITER_OFFSET             5
> +#define GITS_CWRITER_OFFSET_MASK      ((1U << 15) - 1)
> +
> +#define GITS_TYPER_DEVBITS_OFFSET       13
> +#define GITS_TYPER_DEVBITS_MASK        0x1f
> +#define GITS_TYPER_IDBITS_OFFSET        8
> +#define GITS_TYPER_IDBITS_MASK         0x1f
> +#define GITS_TYPER_CIDBITS_OFFSET       32
> +#define GITS_TYPER_CIDBITS_MASK        0xf
> +#define GITS_TYPER_CIL_OFFSET           36
> +#define GITS_TYPER_CIL_MASK             0x1
> +#define GITS_TYPER_PTA_OFFSET           19
> +#define GITS_TYPER_PTA_MASK             0x1
> +#define GITS_TYPER_SEIS_OFFSET          18
> +#define GITS_TYPER_SEIS_MASK            0x1

And here.

> +
> +/* Default features advertised by this version of ITS */
> +/* Physical LPIs supported */
> +#define GITS_TYPER_PHYSICAL           (1U << 0)
> +/*
> + * 11 bytes Interrupt translation Table Entry size
> + * Valid = 1 bit,InterruptType = 1 bit,
> + * Size of LPI number space[considering max 24 bits],
> + * Size of LPI number space[considering max 24 bits],
> + * ICID = 16 bits,
> + * vPEID = 16 bits
> + */
> +#define GITS_TYPER_ITT_ENTRY_OFFSET     4
> +#define GITS_TYPER_ITT_ENTRY_SIZE       0xB
> +#define GITS_TYPER_IDBITS_OFFSET        8
> +
> +/* 16 bits EventId */
> +#define GITS_TYPER_IDBITS             GICD_TYPER_IDBITS
> +/* 16 bits DeviceId */
> +#define GITS_TYPER_DEVBITS            (0xf << 13)
> +/* Collection ID Limit indicated by CIDbits(next) */
> +#define GITS_TYPER_CIL                (1ULL << 36)
> +/* 16 bits CollectionId */
> +#define GITS_TYPER_CIDBITS            (0xfULL << 32)
> +/*
> + * 8 bytes Device Table Entry size
> + * Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits
> + */
> +#define GITS_DTE_SIZE                 (0x8ULL)
> +/*
> + * 8 bytes Collection Table Entry size
> + * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
> + */
> +#define GITS_CTE_SIZE                 (0x8ULL)
> +
>  /* Special interrupt IDs */
>  #define INTID_SECURE 1020
>  #define INTID_NONSECURE 1021
>  #define INTID_SPURIOUS 1023
>  
> +/* ITS Commands */
> +#define GITS_CMD_CLEAR            0x04
> +#define GITS_CMD_DISCARD          0x0F
> +#define GITS_CMD_INT              0x03
> +#define GITS_CMD_MAPC             0x09
> +#define GITS_CMD_MAPD             0x08
> +#define GITS_CMD_MAPI             0x0B
> +#define GITS_CMD_MAPTI            0x0A
> +#define GITS_CMD_SYNC             0x05

Although looking at this patch I suspect the definition of registers
should come in when they are first used.

> +
> +#define GITS_ITT_PAGE_SIZE_0      0x1000
> +#define GITS_ITT_PAGE_SIZE_1      0x4000
> +#define GITS_ITT_PAGE_SIZE_2      0x10000
> +
> +#define GITS_CMDQ_ENTRY_SIZE               32
> +#define GITS_CMDQ_MAX_ENTRIES_PER_PAGE     128
> +#define NUM_BYTES_IN_DW                     8
> +
> +#define CMD_MASK                  0xff
> +
> +/* MAPC command fields */
> +#define ICID_LEN                  16
> +#define ICID_MASK                 ((1U << ICID_LEN) - 1)
> +#define RDBASE_LEN                32
> +#define RDBASE_OFFSET             16
> +#define RDBASE_MASK               ((1ULL << RDBASE_LEN) - 1)
> +#define RDBASE_PROCNUM_LEN        16
> +#define RDBASE_PROCNUM_MASK       ((1ULL << RDBASE_PROCNUM_LEN) - 1)
> +
> +#define DEVID_OFFSET              32
> +#define DEVID_LEN                 32
> +#define DEVID_MASK                ((1ULL << DEVID_LEN) - 1)
> +
> +/* MAPD command fields */
> +#define ITTADDR_LEN               44
> +#define ITTADDR_OFFSET            8
> +#define ITTADDR_MASK              ((1ULL << ITTADDR_LEN) - 1)
> +#define SIZE_MASK                 0x1f
> +
> +/* MAPI command fields */
> +#define EVENTID_MASK              ((1ULL << 32) - 1)
> +
> +/* MAPTI command fields */
> +#define pINTID_OFFSET              32
> +#define pINTID_MASK               ((1ULL << 32) - 1)
> +
> +#define VALID_SHIFT               63
> +#define VALID_MASK                0x1
> +
> +#define L1TABLE_ENTRY_SIZE         8
> +
> +#define LPI_CTE_ENABLE_OFFSET      0
> +#define LPI_CTE_ENABLED          VALID_MASK
> +#define LPI_CTE_PRIORITY_OFFSET    2
> +#define LPI_CTE_PRIORITY_MASK     ((1U << 6) - 1)
> +#define LPI_PRIORITY_MASK         0xfc
> +
>  /* Functions internal to the emulated GICv3 */
>  
>  /**
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..53472239f0 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -8,6 +8,7 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
>    'arm_gicv3_dist.c',
>    'arm_gicv3_its_common.c',
>    'arm_gicv3_redist.c',
> +  'arm_gicv3_its.c',
>  ))
>  softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
>  softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
> diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
> index 5a0952b404..08bc5652ed 100644
> --- a/include/hw/intc/arm_gicv3_its_common.h
> +++ b/include/hw/intc/arm_gicv3_its_common.h
> @@ -25,17 +25,24 @@
>  #include "hw/intc/arm_gicv3_common.h"
>  #include "qom/object.h"
>  
> +#define TYPE_ARM_GICV3_ITS "arm-gicv3-its"
> +
>  #define ITS_CONTROL_SIZE 0x10000
>  #define ITS_TRANS_SIZE   0x10000
>  #define ITS_SIZE         (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
>  
>  #define GITS_CTLR        0x0
>  #define GITS_IIDR        0x4
> +#define GITS_TYPER       0x8
>  #define GITS_CBASER      0x80
>  #define GITS_CWRITER     0x88
>  #define GITS_CREADR      0x90
>  #define GITS_BASER       0x100
>  
> +#define GITS_TRANSLATER  0x0040
> +
> +#define GITS_PIDR2       0xFFE8
> +
>  struct GICv3ITSState {
>      SysBusDevice parent_obj;
>  
> @@ -52,6 +59,8 @@ struct GICv3ITSState {
>      /* Registers */
>      uint32_t ctlr;
>      uint32_t iidr;
> +    uint32_t translater;
> +    uint64_t typer;
>      uint64_t cbaser;
>      uint64_t cwriter;
>      uint64_t creadr;
> @@ -62,7 +71,8 @@ struct GICv3ITSState {
>  
>  typedef struct GICv3ITSState GICv3ITSState;
>  
> -void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
> +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
> +                   const MemoryRegionOps *tops);
>  
>  #define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
>  typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;


-- 
Alex Bennée


  reply	other threads:[~2021-03-25 17:17 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-23  4:12 [PATCH v1 0/8] GICv3 LPI and ITS feature implementation Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 1/8] hw/intc: GICv3 ITS initial framework Shashi Mallela
2021-03-25 16:43   ` Alex Bennée [this message]
2021-03-25 16:43     ` Alex Bennée
2021-03-25 17:18   ` Alex Bennée
2021-03-25 17:18     ` Alex Bennée
2021-03-23  4:12 ` [PATCH v1 2/8] hw/intc: GICv3 ITS register definitions added Shashi Mallela
2021-03-25 19:34   ` Alex Bennée
2021-03-25 19:34     ` Alex Bennée
2021-03-31 16:48     ` shashi.mallela
2021-03-31 16:48       ` shashi.mallela
2021-03-31 23:31       ` Richard Henderson
2021-03-23  4:12 ` [PATCH v1 3/8] hw/intc: GICv3 ITS command queue framework Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 4/8] hw/intc: GICv3 ITS Command processing Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 5/8] hw/intc: GICv3 ITS Feature enablement Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 6/8] hw/intc: GICv3 redistributor ITS processing Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 7/8] hw/arm/sbsa-ref: add ITS support in SBSA GIC Shashi Mallela
2021-03-23  4:12 ` [PATCH v1 8/8] hw/arm/virt: add ITS support in virt GIC Shashi Mallela
2021-03-25 17:59 ` [PATCH v1 0/8] GICv3 LPI and ITS feature implementation Alex Bennée
2021-03-25 17:59   ` Alex Bennée
2021-03-25 19:44 ` Alex Bennée
2021-03-25 19:44   ` Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87r1k3gnk5.fsf@linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=leif@nuviainc.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rad@semihalf.com \
    --cc=shashi.mallela@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.