From: Jinjie Ruan <[email protected]>

MPAMF_ECR and MPAMF_ESR are single per-MSC registers (IHI 0099
4.3), independent of the RIS selection, but the model stored them
per RIS.  Move the live copy to MSC level: ECR/ESR reads and the
extended ESR upper half (guarded on MPAMF_IDR.EXT) come from the
MSC-global view, ECR writes store masked and ESR writes deposit
into either half, and mpam_msc_sync_esr_ecr() keeps the per-RIS
export copies (used by the QMP introspection) in sync.

Signed-off-by: Jinjie Ruan <[email protected]>
---
 hw/arm/mpam.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/hw/arm/mpam.c b/hw/arm/mpam.c
index 6c93ead..fe78adb 100644
--- a/hw/arm/mpam.c
+++ b/hw/arm/mpam.c
@@ -353,6 +353,14 @@ typedef struct MPAMMSCState {
     uint32_t num_csu_mon;
     uint64_t csu_capacity;
 
+    /*
+     * MPAMF_ECR / MPAMF_ESR are single per-MSC registers (IHI 0099 4.3),
+     * independent of the RIS selection.  The 64-bit ESR records the RIS
+     * the error was detected against in its top half.
+     */
+    uint32_t ecr;
+    uint64_t esr;
+
     /*
      * Wired-interrupt GSIVs the board assigned (INTID = SPI + 32).  Zero
      * means "no wired interrupt"; the ACPI MPAM table reports them as-is.
@@ -409,6 +417,20 @@ static uint32_t mpam_nrw_id_for(MPAMMSCState *s, Mpamf 
*mf, uint32_t partid)
     return intpartid % s->num_int_partid;
 }
 
+/*
+ * Keep the per-RIS copies in Mpamf (exported through the QMP/PPTT path)
+ * in sync with the MSC-level ECR/ESR view the MMIO handlers use.
+ */
+static void mpam_msc_sync_esr_ecr(MPAMMSCState *s)
+{
+    int i;
+
+    for (i = 0; i < s->num_ris; i++) {
+        s->mpamf[i].ecr = s->ecr;
+        s->mpamf[i].esr = (uint32_t)s->esr;
+    }
+}
+
 static Mpamf *mpam_mon_ris(MPAMMSCState *s)
 {
     unsigned ris = FIELD_EX32(s->mon_sel, MSMON_CFG_MON_SEL, RIS);
@@ -685,9 +707,16 @@ static uint64_t mpam_msc_read_reg(void *opaque, hwaddr 
offset,
     case A_MPAMF_ERR_MSI_ATTR:
         return mpamf->err_msi_attr;
     case A_MPAMF_ECR:
-        return mpamf->ecr;
+        return s->ecr;
     case A_MPAMF_ESR:
-        return mpamf->esr;
+        return s->esr;
+    case A_MPAMF_ESR + 0x4:
+        if (!FIELD_EX32(mpamf->idr, MPAMF_IDR, EXT)) {
+            qemu_log_mask(LOG_UNIMP,
+                          "MPAM: Unexpected read of extended ESR\n");
+            return 0;
+        }
+        return s->esr >> 32;
     case A_MPAMF_CFG_PART_SEL:
         return mpamf->cfg_part_sel;
     case A_MPAMF_MPAMCFG_INTPARTID: {
@@ -975,7 +1004,20 @@ static void mpam_msc_write_reg(void *opaque, hwaddr 
offset, uint64_t value,
                           "MPAM: Unexpected write to ECR Mask=%x Value=%lx\n",
                           MPAMF_ECR_WRITE_MASK, value);
         }
-        mpamf->ecr = value;
+        s->ecr = value & MPAMF_ECR_WRITE_MASK;
+        mpam_msc_sync_esr_ecr(s);
+        return;
+    case A_MPAMF_ESR:
+        /*
+         * Software clears an error by writing ERRCODE as zero; writing a
+         * non-zero ERRCODE activates the level error interrupt (8.2).
+         */
+        s->esr = deposit64(s->esr, 0, 32, value);
+        mpam_msc_sync_esr_ecr(s);
+        return;
+    case A_MPAMF_ESR + 0x4:
+        s->esr = deposit64(s->esr, 32, 32, value);
+        mpam_msc_sync_esr_ecr(s);
         return;
     default:
         qemu_log_mask(LOG_UNIMP,
-- 
2.43.0


Reply via email to