return false;
}
+ /* Check SSIDSIZE value opted-in is compatible with Host SMMUv3 SSIDSIZE */
+ if (FIELD_EX32(info->idr[1], IDR1, SSIDSIZE) <
+ FIELD_EX32(s->idr[1], IDR1, SSIDSIZE)) {
+ error_setg(errp, "Host SMMUv3 SSIDSIZE not compatible "
+ "(host=%u, QEMU=%u)",
+ FIELD_EX32(info->idr[1], IDR1, SSIDSIZE),
+ FIELD_EX32(s->idr[1], IDR1, SSIDSIZE));
+ return false;
+ }
+
/* User can disable QEMU SMMUv3 Range Invalidation support */
if (FIELD_EX32(info->idr[3], IDR3, RIL) <
FIELD_EX32(s->idr[3], IDR3, RIL)) {
* The real HW nested support should be reported from host SMMUv3 and if
* it doesn't, the nesting parent allocation will fail anyway in VFIO core.
*/
- return VIOMMU_FLAG_WANT_NESTING_PARENT;
+ uint64_t flags = VIOMMU_FLAG_WANT_NESTING_PARENT;
+ SMMUState *bs = opaque;
+ SMMUv3State *s = ARM_SMMUV3(bs);
+
+ if (s->ssidsize) {
+ flags |= VIOMMU_FLAG_PASID_SUPPORTED;
+ }
+ return flags;
}
static const PCIIOMMUOps smmuv3_accel_ops = {
if (s->oas == SMMU_OAS_48BIT) {
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
}
+
+ /*
+ * By default QEMU SMMUv3 has no SubstreamID support. Update IDR1 if user
+ * has enabled it.
+ */
+ s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SSIDSIZE, s->ssidsize);
}
/* Based on SMUUv3 GPBA.ABORT configuration, attach a corresponding HWPT */
}
}
- if (STE_S1CDMAX(ste) != 0) {
+ /* Multiple context descriptors require SubstreamID support */
+ if (!s->ssidsize && STE_S1CDMAX(ste) != 0) {
qemu_log_mask(LOG_UNIMP,
- "SMMUv3 does not support multiple context descriptors yet\n");
+ "SMMUv3: multiple S1 context descriptors require SubstreamID support. "
+ "Configure ssidsize > 0 (requires accel=on)\n");
goto bad_ste;
}
error_setg(errp, "OAS must be 44 bits when accel=off");
return false;
}
+ if (s->ssidsize) {
+ error_setg(errp, "ssidsize can only be set if accel=on");
+ return false;
+ }
return true;
}
error_setg(errp, "OAS can only be set to 44 or 48 bits");
return false;
}
+ if (s->ssidsize > SMMU_SSID_MAX_BITS) {
+ error_setg(errp, "ssidsize must be in the range 0 to %d",
+ SMMU_SSID_MAX_BITS);
+ return false;
+ }
return true;
}
DEFINE_PROP_BOOL("ril", SMMUv3State, ril, true),
DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false),
DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44),
+ DEFINE_PROP_UINT8("ssidsize", SMMUv3State, ssidsize, 0),
};
static void smmuv3_instance_init(Object *obj)
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");
+ object_class_property_set_description(klass, "ssidsize",
+ "Number of bits used to represent SubstreamIDs (SSIDs). "
+ "A value of N allows SSIDs in the range [0 .. 2^N - 1]. "
+ "Valid range is 0-20, where 0 disables SubstreamID support. "
+ "Defaults to 0. A value greater than 0 is required to enable "
+ "PASID support.");
}
static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,