On Fri, 16 Oct 2026 17:47:00 +0800
Jinjie Ruan <[email protected]> wrote:

> From: Jonathan Cameron <[email protected]>
> 
> Add the mpam-msc sysbus device core:
> - Per-RIS register storage(Mpamf)
> - The device state (selector state, num-ris/num-partid/
>   num-int-partid properties), realize with the per-RIS allocation
>   and the MMIO region (MPAM_SIZE window).
> - The MMIO handlers covering the identification registers (MPAMF_IDR
>   with its 64-bit EXT view IIDR, AIDR, IMPL_IDR, PARTID_NRW_IDR
>   and the MSMON IDRs that read as zero until monitoring is implemented).
> 
> The base type registers no features; the mpam-msc-mem and
> mpam-msc-cache subtypes assemble their feature IDR fields.
> 
> Based on an RFC series by Jonathan Cameron.
> 
> Signed-off-by: Jonathan Cameron <[email protected]>
> Signed-off-by: Jinjie Ruan <[email protected]>

A few trivial things inline.

> ---
>  hw/arm/mpam.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 171 insertions(+)
> 
> diff --git a/hw/arm/mpam.c b/hw/arm/mpam.c
> index 772a120..b1d6472 100644
> --- a/hw/arm/mpam.c
> +++ b/hw/arm/mpam.c
> @@ -221,3 +221,174 @@ REG32(MPAMF_MPAMCFG_MBW_PBM0, 0x2000)
>  #define MPAM_CACHE_PART 32
>  /* MPAMF_IIDR.IMPLEMENTER: ARM JEP106 code for Huawei (0x736). */
>  #define MPAM_IIDR_IMPLEMENTER 0x736
> +
> +typedef struct Mpamf {
> +    uint64_t idr;
> +    uint32_t iidr;
> +    uint32_t aidr;
> +    uint32_t impl_idr;
> +    uint32_t cpor_idr;
> +    uint32_t ccap_idr;
> +    uint32_t mbw_idr;
> +    uint32_t pri_idr;
> +    uint32_t partid_nrw_idr;
> +    uint32_t msmon_idr;
> +    uint32_t csumon_idr;
> +    uint32_t mbwumon_idr;
> +    uint32_t err_msi_mpam;
> +    uint32_t err_msi_addr_l;
> +    uint32_t err_msi_addr_h;
> +    uint32_t err_msi_data;
> +    uint32_t err_msi_attr;
> +    uint32_t ecr;
> +    uint32_t esr;
> +    uint32_t cfg_part_sel;
> +} Mpamf;
> +
> +typedef struct MPAMMSCState {
> +    SysBusDevice parent_obj;
> +
> +    Mpamf *mpamf;
> +
> +    uint8_t ris;
> +    uint16_t part_sel; /* Technically per ris, but in same reg */
> +    bool internal_part_sel;
> +    struct MemoryRegion mr;
> +    uint32_t num_partid;
> +    uint32_t num_int_partid;
> +    uint8_t num_ris;
> +

Blank line seems pointless. Probably belongs in some later patch.

> +} MPAMMSCState;
> +
> +DECLARE_INSTANCE_CHECKER(MPAMMSCState, MPAM_MSC_DEVICE, TYPE_MPAM_MSC);
> +
> +static uint64_t mpam_msc_read_reg(void *opaque, hwaddr offset,
> +                                  unsigned size)
> +{
> +    MPAMMSCState *s = MPAM_MSC_DEVICE(opaque);
> +    Mpamf *mpamf = &s->mpamf[s->ris];
> +
> +    switch (offset) {
> +    case A_MPAMF_IDR:
> +        switch (size) {
> +        case 4:
> +            return mpamf->idr & 0xffffffff;

Maybe use MAKE_64BIT_MASK(0, 32) from qemu/bitops.h


> +        case 8:
> +            return mpamf->idr;
> +        default:
> +            qemu_log_mask(LOG_UNIMP, "MPAM: Unexpected read size\n");
> +            return 0;
> +        }
> +    case A_MPAMF_IDR + 0x04:
> +        if (!FIELD_EX32(mpamf->idr, MPAMF_IDR, EXT)) {
> +            qemu_log_mask(LOG_UNIMP, "MPAM: Unexpected read of top of 
> IDR\n");
> +            return 0;
> +        }
> +        switch (size) {
> +        case 4:
> +            return mpamf->idr >> 32;
> +        default:
> +            qemu_log_mask(LOG_UNIMP, "MPAM: Unexpected read size\n");
> +            return 0;
> +        }
> +    case A_MPAMF_IIDR:

Not sure why I allowed 1 byte reads. Probably want to check each of
the read widths for 4 or 8 though as appropriate.

> +        return mpamf->iidr;
> +    case A_MPAMF_AIDR:
> +        return mpamf->aidr;
> +    case A_MPAMF_IMPL_IDR:
> +        if (!FIELD_EX32(mpamf->idr, MPAMF_IDR, HAS_IMPL_IDR)) {
> +            qemu_log_mask(LOG_UNIMP,
> +                "MPAM: Accessing IMPL_IDR which isn't suported\n");
> +            return 0;
> +        }
> +        return mpamf->impl_idr;
> +    case A_MPAMF_PARTID_NRW_IDR: {
> +        return mpamf->partid_nrw_idr;
> +    }
> +    case A_MPAMF_MSMON_IDR:
> +        return mpamf->msmon_idr;
> +    case A_MPAMF_CSUMON_IDR:
> +        return mpamf->csumon_idr;
> +    case A_MPAMF_MBWUMON_IDR:
> +        return mpamf->mbwumon_idr;
> +    default:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "MPAM: Unexpected read of %lx\n", offset);
> +        return 0x0;
> +    }
> +}

> +
> +static void mpam_msc_realize(DeviceState *dev, Error **errp)
> +{
> +    MPAMMSCState *s = MPAM_MSC_DEVICE(dev);
> +
> +    /* IHI 0099: MPAMF_CFG_PART_SEL.RIS is 4 bits, so at most 16 RIS. */

Hmm. I wonder if this changed name.  The spec now has MPAMCFG_PART_SEL.
Should match that naming I suppose.


> +    if (s->num_ris > 16) {
> +        error_setg(errp, "num-ris must be <= 16");
> +        return;
> +    }
> +    if (s->num_partid == 0) {
> +        error_setg(errp, "num-ris must be <= 16");
> +        return;
> +    }
> +    if (s->num_int_partid == 0) {
> +        s->num_int_partid = s->num_partid;
> +    }
> +
> +    s->mpamf = g_new0(Mpamf, s->num_ris);
> +    memory_region_init_io(&s->mr, OBJECT(s), &mpam_msc_ops, s, "mpam_msc",
> +                          MPAM_SIZE);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
> +}



Reply via email to