#include "smmuv3-internal.h"
#include "smmuv3-accel.h"
+#include "system/system.h"
/*
* The root region aliases the global system memory, and shared_as_sysmem
return map[oas];
}
+static void smmuv3_accel_auto_finalise(SMMUv3State *s,
+ struct iommu_hw_info_arm_smmuv3 *info)
+{
+ SMMUv3AccelState *accel = s->s_accel;
+
+ /*
+ * Return if 'auto' was not set for any accel SMMUv3 property, or
+ * if property values were already resolved from a previous call
+ * to this function (e.g. if this function was called again after
+ * VM boot during device hot plug). We do not accept new property
+ * values in this case where auto_finalised == true, and we re-use
+ * the values determined from the initial cold plug.
+ */
+ if (!accel->auto_mode || accel->auto_finalised) {
+ return;
+ }
+
+ accel->auto_finalised = true;
+}
+
static bool
smmuv3_accel_check_hw_compatible(SMMUv3State *s,
struct iommu_hw_info_arm_smmuv3 *info,
Error **errp)
{
+ smmuv3_accel_auto_finalise(s, info);
+
/* 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)) {
address_space_init(shared_as_sysmem, &root, "smmuv3-accel-as-sysmem");
}
+static void smmuv3_accel_machine_done(Notifier *notifier, void *data)
+{
+ SMMUv3State *s = container_of(notifier, SMMUv3State, machine_done);
+ SMMUv3AccelState *accel = s->s_accel;
+
+ if (accel->auto_mode && !accel->auto_finalised) {
+ error_report("arm-smmuv3 accel=on with 'auto' properties requires "
+ "at least one cold-plugged VFIO device");
+ exit(1);
+ }
+}
+
bool smmuv3_accel_init(SMMUv3State *s, Error **errp)
{
SMMUState *bs = ARM_SMMU(s);
s->s_accel = g_new0(SMMUv3AccelState, 1);
bs->iommu_ops = &smmuv3_accel_ops;
smmuv3_accel_as_init(s);
+
+ if (s->s_accel->auto_mode) {
+ s->machine_done.notify = smmuv3_accel_machine_done;
+ qemu_add_machine_init_done_notifier(&s->machine_done);
+ }
+
return true;
}