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 <[email protected]> Signed-off-by: Shameer Kolothum <[email protected]> --- 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
