QEMU SMMUv3 currently sets the output address size (OAS) to 44 bits. With
accelerator mode enabled, a guest device may use SVA where CPU page tables
are shared with SMMUv3, requiring OAS at least equal to the CPU OAS. Add
a user option to set this.

Note: Linux kernel docs currently state the OAS field in the IDR register
is not meaningful for users. But looks like we need this information.

Signed-off-by: Shameer Kolothum <[email protected]>
---
 hw/arm/smmuv3-accel.c    | 15 +++++++++++++++
 hw/arm/smmuv3-internal.h |  3 ++-
 hw/arm/smmuv3.c          | 15 ++++++++++++++-
 include/hw/arm/smmuv3.h  |  1 +
 4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index eee54316bf..ba37d690ad 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -86,6 +86,17 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
         return false;
     }
 
+    /*
+     * ToDo: OAS is not something Linux kernel doc says meaningful for user.
+     * But looks like OAS needs to be compatibe for accelerator support. Please
+     * check.
+     */
+    val = FIELD_EX32(info->idr[5], IDR5, OAS);
+    if (val < FIELD_EX32(s->idr[5], IDR5, OAS)) {
+        error_setg(errp, "Host SUMMUv3 OAS not compatible");
+        return false;
+    }
+
     val = FIELD_EX32(info->idr[5], IDR5, GRAN4K);
     if (val != FIELD_EX32(s->idr[5], IDR5, GRAN4K)) {
         error_setg(errp, "Host SMMUv3 doesn't support 64K translation 
granule");
@@ -648,6 +659,10 @@ void smmuv3_accel_idr_override(SMMUv3State *s)
     if (s->ats) {
         s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ATS, 1); /* ATS */
     }
+    /* QEMU SMMUv3 has oas set 44. Update IDR5 if user has it set to 48 bits*/
+    if (s->oas == 48) {
+        s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
+    }
 }
 
 /*
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index b0dfa9465c..910a34e05b 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -111,7 +111,8 @@ REG32(IDR5,                0x14)
      FIELD(IDR5, VAX,        10, 2);
      FIELD(IDR5, STALL_MAX,  16, 16);
 
-#define SMMU_IDR5_OAS 4
+#define SMMU_IDR5_OAS_44 4
+#define SMMU_IDR5_OAS_48 5
 
 REG32(IIDR,                0x18)
 REG32(AIDR,                0x1c)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 77d46a9cd6..7c391ab711 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -294,7 +294,8 @@ static void smmuv3_init_regs(SMMUv3State *s)
     s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
     s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
 
-    s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
+    /* OAS: 44 bits */
+    s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44);
     /* 4K, 16K and 64K granule support */
     s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
     s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1);
@@ -1943,6 +1944,10 @@ static bool smmu_validate_property(SMMUv3State *s, Error 
**errp)
     }
 #endif
     if (s->accel) {
+        if (s->oas != 44 && s->oas != 48) {
+            error_setg(errp, "oas can only be set to 44 or 48 bits");
+            return false;
+        }
         return true;
     }
     if (!s->ril) {
@@ -1953,6 +1958,10 @@ static bool smmu_validate_property(SMMUv3State *s, Error 
**errp)
         error_setg(errp, "ats can only be enabled if accel=on");
         return false;
     }
+    if (s->oas != 44) {
+        error_setg(errp, "oas can only be set to 44 bits if accel=off");
+        return false;
+    }
     return true;
 }
 
@@ -2078,6 +2087,7 @@ static const Property smmuv3_properties[] = {
     /* RIL can be turned off for accel cases */
     DEFINE_PROP_BOOL("ril", SMMUv3State, ril, true),
     DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false),
+    DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44),
 };
 
 static void smmuv3_instance_init(Object *obj)
@@ -2110,6 +2120,9 @@ static void smmuv3_class_init(ObjectClass *klass, const 
void *data)
     object_class_property_set_description(klass, "ats",
         "Enable/disable ATS support. Please ensure host platform has ATS "
         "support before enabling this");
+    object_class_property_set_description(klass, "oas",
+        "Specify Output Address Size. Supported values are 44 or 48 bits "
+        "Defaults to 44 bits");
 }
 
 static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index 6f07baa144..d3788b2d85 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -70,6 +70,7 @@ struct SMMUv3State {
     Error  *migration_blocker;
     bool ril;
     bool ats;
+    uint8_t oas;
 };
 
 typedef enum {
-- 
2.43.0


Reply via email to