Just before the device gets attached to the SMMUv3, make sure QEMU SMMUv3 features are compatible with the host SMMUv3.
Not all fields in the host SMMUv3 IDR registers are meaningful for userspace. Only the following fields can be used: - IDR0: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN, CD2L, ASID16, TTF - IDR1: SIDSIZE, SSIDSIZE - IDR3: BBML, RIL - IDR5: VAX, GRAN64K, GRAN16K, GRAN4K For now, the check is to make sure the features are in sync to enable basic accelerated SMMUv3 support. AIDR is not checked, as hardware implementations often provide a mix of architecture features regardless of the revision reported in AIDR. Note that SSIDSIZE check will be added later when support for PASID is introduced. Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Eric Auger <[email protected]> Signed-off-by: Shameer Kolothum <[email protected]> --- hw/arm/smmuv3-accel.c | 95 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c index a7291e75f1..aae7840c40 100644 --- a/hw/arm/smmuv3-accel.c +++ b/hw/arm/smmuv3-accel.c @@ -27,6 +27,93 @@ static MemoryRegion root, sysmem; static AddressSpace *shared_as_sysmem; +static bool +smmuv3_accel_check_hw_compatible(SMMUv3State *s, + struct iommu_hw_info_arm_smmuv3 *info, + Error **errp) +{ + /* QEMU SMMUv3 supports both linear and 2-level stream tables */ + if (FIELD_EX32(info->idr[0], IDR0, STLEVEL) != + FIELD_EX32(s->idr[0], IDR0, STLEVEL)) { + error_setg(errp, "Host SMMUv3 differs in Stream Table format"); + return false; + } + + /* QEMU SMMUv3 supports only little-endian translation table walks */ + if (FIELD_EX32(info->idr[0], IDR0, TTENDIAN) > + FIELD_EX32(s->idr[0], IDR0, TTENDIAN)) { + error_setg(errp, "Host SMMUv3 doesn't support Little-endian " + "translation table"); + return false; + } + + /* QEMU SMMUv3 supports only AArch64 translation table format */ + if (FIELD_EX32(info->idr[0], IDR0, TTF) < + FIELD_EX32(s->idr[0], IDR0, TTF)) { + error_setg(errp, "Host SMMUv3 doesn't support AArch64 translation " + "table format"); + return false; + } + + /* QEMU SMMUv3 supports SIDSIZE 16 */ + if (FIELD_EX32(info->idr[1], IDR1, SIDSIZE) < + FIELD_EX32(s->idr[1], IDR1, SIDSIZE)) { + error_setg(errp, "Host SMMUv3 SIDSIZE not compatible"); + return false; + } + + /* QEMU SMMUv3 supports Range Invalidation by default */ + if (FIELD_EX32(info->idr[3], IDR3, RIL) != + FIELD_EX32(s->idr[3], IDR3, RIL)) { + error_setg(errp, "Host SMMUv3 doesn't support Range Invalidation"); + 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)) { + error_setg(errp, "Host SMMUv3 doesn't support 4K translation granule"); + return false; + } + if (FIELD_EX32(info->idr[5], IDR5, GRAN16K) != + FIELD_EX32(s->idr[5], IDR5, GRAN16K)) { + error_setg(errp, "Host SMMUv3 doesn't support 16K translation granule"); + return false; + } + if (FIELD_EX32(info->idr[5], IDR5, GRAN64K) != + FIELD_EX32(s->idr[5], IDR5, GRAN64K)) { + error_setg(errp, "Host SMMUv3 doesn't support 64K translation granule"); + return false; + } + + return true; +} + +static bool +smmuv3_accel_hw_compatible(SMMUv3State *s, HostIOMMUDeviceIOMMUFD *idev, + Error **errp) +{ + struct iommu_hw_info_arm_smmuv3 info; + uint32_t data_type; + uint64_t caps; + + if (!iommufd_backend_get_device_info(idev->iommufd, idev->devid, &data_type, + &info, sizeof(info), &caps, errp)) { + return false; + } + + if (data_type != IOMMU_HW_INFO_TYPE_ARM_SMMUV3) { + error_setg(errp, "Wrong data type (%d) for Host SMMUv3 device info", + data_type); + return false; + } + + if (!smmuv3_accel_check_hw_compatible(s, &info, errp)) { + return false; + } + return true; +} + static SMMUv3AccelDevice *smmuv3_accel_get_dev(SMMUState *bs, SMMUPciBus *sbus, PCIBus *bus, int devfn) { @@ -352,6 +439,14 @@ static bool smmuv3_accel_set_iommu_device(PCIBus *bus, void *opaque, int devfn, return true; } + /* + * Check the host SMMUv3 associated with the dev is compatible with the + * QEMU SMMUv3 accel. + */ + if (!smmuv3_accel_hw_compatible(s, idev, errp)) { + return false; + } + if (s->s_accel) { goto done; } -- 2.43.0
