[PATCH v5 28/32] hw/arm/smmuv3-accel: Add property to specify OAS bits

Shameer Kolothum posted 32 patches 1 week, 6 days ago
[PATCH v5 28/32] hw/arm/smmuv3-accel: Add property to specify OAS bits
Posted by Shameer Kolothum 1 week, 6 days ago
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.

Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
---
 hw/arm/smmuv3-accel.c    | 22 ++++++++++++++++++++++
 hw/arm/smmuv3-internal.h |  3 ++-
 hw/arm/smmuv3.c          | 16 +++++++++++++++-
 include/hw/arm/smmuv3.h  |  1 +
 4 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index 5b0ef3804a..c46510150e 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -28,6 +28,12 @@ MemoryRegion root;
 MemoryRegion sysmem;
 static AddressSpace *shared_as_sysmem;
 
+static int smmuv3_oas_bits(uint32_t oas)
+{
+    static const int map[] = { 32, 36, 40, 42, 44, 48, 52, 56 };
+    return (oas < ARRAY_SIZE(map)) ? map[oas] : -EINVAL;
+}
+
 static bool
 smmuv3_accel_check_hw_compatible(SMMUv3State *s,
                                  struct iommu_hw_info_arm_smmuv3 *info,
@@ -70,6 +76,18 @@ 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 compatible for accelerator support. Please
+     * check.
+     */
+    if (FIELD_EX32(info->idr[5], IDR5, OAS) <
+                FIELD_EX32(s->idr[5], IDR5, OAS)) {
+        error_setg(errp, "Host SMMUv3 OAS(%d) bits not compatible",
+                   smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)));
+        return false;
+    }
+
     /* QEMU SMMUv3 supports GRAN4K/GRAN16K/GRAN64K translation granules */
     if (FIELD_EX32(info->idr[5], IDR5, GRAN4K) !=
                 FIELD_EX32(s->idr[5], IDR5, GRAN4K)) {
@@ -649,6 +667,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);
+    }
 }
 
 /* Based on SMUUv3 GBPA configuration, attach a corresponding HWPT */
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 5fd88b4257..cfc5897569 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 d95279a733..c4d28a3786 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -299,7 +299,8 @@ static void smmuv3_init_id_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);
@@ -1961,6 +1962,15 @@ 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 false;
+    }
+
+    if (s->oas != 44 && s->oas != 48) {
+        error_setg(errp, "OAS can only be set to 44 or 48 bits");
         return false;
     }
     return true;
@@ -2087,6 +2097,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)
@@ -2119,6 +2130,9 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
     object_class_property_set_description(klass, "ats",
         "Enable/disable ATS support (for accel=on). Please ensure host "
         "platform has ATS support before enabling this");
+    object_class_property_set_description(klass, "oas",
+        "Specify Output Address Size (for accel =on). 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 5fd5ec7b49..e4226b66f3 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
Re: [PATCH v5 28/32] hw/arm/smmuv3-accel: Add property to specify OAS bits
Posted by Eric Auger 1 week, 2 days ago

On 10/31/25 11:50 AM, Shameer Kolothum wrote:
> 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.
I would explain why this is actually needed instead of quoting the linux
kernel docs. I guess in practice the vSMMU can't advertise an OAS
greater than the one support by the host SMMU otherwise the guest might
fail to use the range exposed by the vSMMU.
>
> Tested-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
> ---
>  hw/arm/smmuv3-accel.c    | 22 ++++++++++++++++++++++
>  hw/arm/smmuv3-internal.h |  3 ++-
>  hw/arm/smmuv3.c          | 16 +++++++++++++++-
>  include/hw/arm/smmuv3.h  |  1 +
>  4 files changed, 40 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
> index 5b0ef3804a..c46510150e 100644
> --- a/hw/arm/smmuv3-accel.c
> +++ b/hw/arm/smmuv3-accel.c
> @@ -28,6 +28,12 @@ MemoryRegion root;
>  MemoryRegion sysmem;
>  static AddressSpace *shared_as_sysmem;
>  
> +static int smmuv3_oas_bits(uint32_t oas)
> +{
> +    static const int map[] = { 32, 36, 40, 42, 44, 48, 52, 56 };
> +    return (oas < ARRAY_SIZE(map)) ? map[oas] : -EINVAL;
> +}
> +
>  static bool
>  smmuv3_accel_check_hw_compatible(SMMUv3State *s,
>                                   struct iommu_hw_info_arm_smmuv3 *info,
> @@ -70,6 +76,18 @@ 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 compatible for accelerator support. Please
> +     * check.
would remove that comment. Either it is requested or not.
> +     */
> +    if (FIELD_EX32(info->idr[5], IDR5, OAS) <
> +                FIELD_EX32(s->idr[5], IDR5, OAS)) {
> +        error_setg(errp, "Host SMMUv3 OAS(%d) bits not compatible",
> +                   smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)));
let's be more explicit then and say

Host SMMUv3 OAS (%d bits) is less that OAS bits advertised by SMMU (%d)



> +        return false;
> +    }
> +
>      /* QEMU SMMUv3 supports GRAN4K/GRAN16K/GRAN64K translation granules */
>      if (FIELD_EX32(info->idr[5], IDR5, GRAN4K) !=
>                  FIELD_EX32(s->idr[5], IDR5, GRAN4K)) {
> @@ -649,6 +667,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*/
vSMMUv3 advertises by default a 44 bit wide OAS
> +    if (s->oas == 48) {
> +        s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
> +    }
>  }
>  
>  /* Based on SMUUv3 GBPA configuration, attach a corresponding HWPT */
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index 5fd88b4257..cfc5897569 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 d95279a733..c4d28a3786 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -299,7 +299,8 @@ static void smmuv3_init_id_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);
> @@ -1961,6 +1962,15 @@ 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 false;
> +    }
> +
> +    if (s->oas != 44 && s->oas != 48) {
> +        error_setg(errp, "OAS can only be set to 44 or 48 bits");
>          return false;
>      }
>      return true;
> @@ -2087,6 +2097,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)
> @@ -2119,6 +2130,9 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
>      object_class_property_set_description(klass, "ats",
>          "Enable/disable ATS support (for accel=on). Please ensure host "
>          "platform has ATS support before enabling this");
> +    object_class_property_set_description(klass, "oas",
> +        "Specify Output Address Size (for accel =on). 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 5fd5ec7b49..e4226b66f3 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 {
Re: [PATCH v5 28/32] hw/arm/smmuv3-accel: Add property to specify OAS bits
Posted by Jason Gunthorpe 1 week, 2 days ago
On Tue, Nov 04, 2025 at 03:35:42PM +0100, Eric Auger wrote:
> > +    /*
> > +     * TODO: OAS is not something Linux kernel doc says meaningful for user.
> > +     * But looks like OAS needs to be compatible for accelerator support. Please
> > +     * check.
> would remove that comment. Either it is requested or not.
> > +     */
> > +    if (FIELD_EX32(info->idr[5], IDR5, OAS) <
> > +                FIELD_EX32(s->idr[5], IDR5, OAS)) {
> > +        error_setg(errp, "Host SMMUv3 OAS(%d) bits not compatible",
> > +                   smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)));
> let's be more explicit then and say
> 
> Host SMMUv3 OAS (%d bits) is less that OAS bits advertised by SMMU (%d)

It isn't OAS that is being checked here, this is now IPA. OAS is for
use by the hypervisor.

When the guest looks at the vSMMU the "OAS" it sees is the IPS
supported by the HW.

Aside from the raw HW limit, it also shouldn't exceed the configured
size of the S2 HWPT.

So the above should refer to this detail because it is a bit subtle
that OAS and IPS are often the same. See "3.4 Address sizes"

* IAS reflects the maximum usable IPA of an implementation that is
  generated by stage 1 and input to stage 2:

- This term is defined to illustrate the handling of intermediate
  addresses in this section and is not a configurable parameter.

- The maximum usable IPA size of an SMMU is defined in terms of other SMMU implementation choices,
  as:
    IAS = MAX(SMMU_IDR0.TTF[0]==1 ? 40 : 0), SMMU_IDR0.TTF[1]==1 ? OAS : 0));

- An IPA of 40 bits is required to support of AArch32 LPAE translations, and AArch64 limits the
maximum IPA size to the maximum PA size. Otherwise, when AArch32 LPAE is not implemented, the
IPA size equals OAS, the PA size, and might be smaller than 40 bits.

- The purpose of definition of the IAS term is to abstract away from these implementation variables.

Jason
Re: [PATCH v5 28/32] hw/arm/smmuv3-accel: Add property to specify OAS bits
Posted by Eric Auger 1 week, 1 day ago
Hi Jason,

On 11/4/25 3:50 PM, Jason Gunthorpe wrote:
> On Tue, Nov 04, 2025 at 03:35:42PM +0100, Eric Auger wrote:
>>> +    /*
>>> +     * TODO: OAS is not something Linux kernel doc says meaningful for user.
>>> +     * But looks like OAS needs to be compatible for accelerator support. Please
>>> +     * check.
>> would remove that comment. Either it is requested or not.
>>> +     */
>>> +    if (FIELD_EX32(info->idr[5], IDR5, OAS) <
>>> +                FIELD_EX32(s->idr[5], IDR5, OAS)) {
>>> +        error_setg(errp, "Host SMMUv3 OAS(%d) bits not compatible",
>>> +                   smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)));
>> let's be more explicit then and say
>>
>> Host SMMUv3 OAS (%d bits) is less that OAS bits advertised by SMMU (%d)
> It isn't OAS that is being checked here, this is now IPA. OAS is for
> use by the hypervisor.
>
> When the guest looks at the vSMMU the "OAS" it sees is the IPS
> supported by the HW.
>
> Aside from the raw HW limit, it also shouldn't exceed the configured
> size of the S2 HWPT.
>
> So the above should refer to this detail because it is a bit subtle
> that OAS and IPS are often the same. See "3.4 Address sizes"
>
> * IAS reflects the maximum usable IPA of an implementation that is
>   generated by stage 1 and input to stage 2:
>
> - This term is defined to illustrate the handling of intermediate
>   addresses in this section and is not a configurable parameter.
>
> - The maximum usable IPA size of an SMMU is defined in terms of other SMMU implementation choices,
>   as:
>     IAS = MAX(SMMU_IDR0.TTF[0]==1 ? 40 : 0), SMMU_IDR0.TTF[1]==1 ? OAS : 0));
>
> - An IPA of 40 bits is required to support of AArch32 LPAE translations, and AArch64 limits the
> maximum IPA size to the maximum PA size. Otherwise, when AArch32 LPAE is not implemented, the
> IPA size equals OAS, the PA size, and might be smaller than 40 bits.
>
> - The purpose of definition of the IAS term is to abstract away from these implementation variables.
Thank you for the clarification and pointer. I fully agree.
maybe we can rephrase the error msg as:

"Host SMMUv3 OAS (%d bits) is less that physical SMMU maximum usable IPA (%d)"
which is more accurate despite in practice here we assimilate max IPA to OAS (
TTF[1]==1 case)

Eric

>
> Jason
>