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 Stream Table format mismatch "
+ "(host STLEVEL=%u, QEMU STLEVEL=%u)",
+ FIELD_EX32(info->idr[0], IDR0, STLEVEL),
+ FIELD_EX32(s->idr[0], IDR0, STLEVEL));
+ 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 "
+ "(host=%u, QEMU=%u)",
+ FIELD_EX32(info->idr[1], IDR1, SIDSIZE),
+ FIELD_EX32(s->idr[1], IDR1, SIDSIZE));
+ 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)
{
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->viommu) {
goto done;
}