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); > +}
