@@ -3,7 +3,7 @@ GVT_DIR := gvt
GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
execlist.o scheduler.o sched_policy.o mmio_context.o cmd_parser.o debugfs.o \
- fb_decoder.o dmabuf.o page_track.o migrate.o
+ fb_decoder.o dmabuf.o page_track.o migrate.o migration_version.o
ccflags-y += -I $(srctree)/$(src) -I $(srctree)/$(src)/$(GVT_DIR)/
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
@@ -106,14 +106,53 @@ static ssize_t description_show(struct kobject *kobj, struct device *dev,
type->weight);
}
+static ssize_t migration_version_show(struct kobject *kobj, struct device *dev,
+ char *buf)
+{
+ struct intel_vgpu_type *type;
+ void *gvt = kdev_to_i915(dev)->gvt;
+
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+ if (!type || !type->migration_version) {
+ gvt_err("Migration not supported on type %s. Please search previous detailed log\n",
+ kobject_name(kobj));
+ return -ENODEV;
+ }
+
+ return snprintf(buf, strlen(type->migration_version) + 2,
+ "%s\n", type->migration_version);
+}
+
+static ssize_t migration_version_store(struct kobject *kobj, struct device *dev,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ struct intel_vgpu_type *type;
+ void *gvt = kdev_to_i915(dev)->gvt;
+
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
+ if (!type || !type->migration_version) {
+ gvt_err("Migration not supported on type %s. Please search previous detailed log\n",
+ kobject_name(kobj));
+ return -ENODEV;
+ }
+
+ ret = intel_gvt_check_vfio_migration_version(gvt,
+ type->migration_version, buf);
+
+ return (ret < 0 ? ret : count);
+}
+
static MDEV_TYPE_ATTR_RO(available_instances);
static MDEV_TYPE_ATTR_RO(device_api);
static MDEV_TYPE_ATTR_RO(description);
+static MDEV_TYPE_ATTR_RW(migration_version);
static struct attribute *gvt_type_attrs[] = {
&mdev_type_attr_available_instances.attr,
&mdev_type_attr_device_api.attr,
&mdev_type_attr_description.attr,
+ &mdev_type_attr_migration_version.attr,
NULL,
};
@@ -277,6 +277,7 @@ struct intel_vgpu_type {
unsigned int fence;
unsigned int weight;
enum intel_vgpu_edid resolution;
+ char *migration_version;
};
struct intel_gvt {
@@ -709,6 +710,10 @@ int submit_context(struct intel_vgpu *vgpu,
struct execlist_ctx_descriptor_format *desc,
bool emulate_schedule_in);
+ssize_t intel_gvt_check_vfio_migration_version(struct intel_gvt *gvt,
+ const char *self, const char *remote);
+char *intel_gvt_get_vfio_migration_version(struct intel_gvt *gvt,
+ const char *vgpu_type);
#include "trace.h"
#include "mpt.h"
new file mode 100644
@@ -0,0 +1,170 @@
+/*
+ * Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Yan Zhao <yan.y.zhao@intel.com>
+ */
+#include <linux/vfio.h>
+#include "i915_drv.h"
+#include "gvt.h"
+
+#define INV_SOFTWARE_VERSION (-1U)
+#define VENDOR_ID_LEN (4)
+#define DEVICE_ID_LEN (4)
+#define VGPU_TYPE_LEN (16)
+#define SOFTWARE_VER_LEN (8)
+
+/* total length of vfio migration version string.
+ * never exceed limit of PATH_MAX (4096)
+ */
+#define MIGRATION_VERSION_TOTAL_LEN (VENDOR_ID_LEN + DEVICE_ID_LEN + \
+ VGPU_TYPE_LEN + SOFTWARE_VER_LEN + 4)
+
+#define GVT_VFIO_MIGRATION_SOFTWARE_VERSION INV_SOFTWARE_VERSION
+
+
+#define PRINTF_FORMAT "%04x-%04x-%s-%08x"
+#define SCANF_FORMAT "%x-%x-%16[^-]-%x"
+
+enum incompatible_reason {
+ IREASON_WRONG_REMOTE_FORMAT = 0,
+ IREASON_HARDWARE_MISMATCH,
+ IREASON_SOFTWARE_VERSION_MISMATCH,
+ IREASON_VGPU_TYPE_MISMATCH,
+};
+
+static const char *const incompatible_reason_str[] = {
+ [IREASON_WRONG_REMOTE_FORMAT] =
+ "wrong string format. probably wrong GVT version",
+ [IREASON_HARDWARE_MISMATCH] =
+ "physical device not matched",
+ [IREASON_SOFTWARE_VERSION_MISMATCH] =
+ "migration software version not matched",
+ [IREASON_VGPU_TYPE_MISMATCH] =
+ "vgpu type not matched"
+};
+
+static bool is_compatible(const char *local, const char *remote)
+{
+ bool ret;
+
+ ret = sysfs_streq(local, remote);
+
+ if (!ret) {
+ int vid_l = 0, did_l = 0, vid_r = 0, did_r = 0;
+ char type_l[VGPU_TYPE_LEN], type_r[VGPU_TYPE_LEN];
+ u32 sv_l = 0, sv_r = 0;
+ int rl = 0, rr = 0;
+ enum incompatible_reason reason = IREASON_WRONG_REMOTE_FORMAT;
+
+ memset(type_l, 0, sizeof(type_l));
+ memset(type_r, 0, sizeof(type_r));
+
+ rl = sscanf(local, SCANF_FORMAT,
+ &vid_l, &did_l, type_l, &sv_l);
+ rr = sscanf(remote, SCANF_FORMAT,
+ &vid_r, &did_r, type_r, &sv_r);
+
+ if (rl == rr) {
+ if (vid_l != vid_r || did_l != did_r)
+ reason = IREASON_HARDWARE_MISMATCH;
+ else if (sv_l != sv_r)
+ reason = IREASON_SOFTWARE_VERSION_MISMATCH;
+ else if (strncmp(type_l, type_r, VGPU_TYPE_LEN))
+ reason = IREASON_VGPU_TYPE_MISMATCH;
+ }
+
+ gvt_err("Migration version mismatched. Possible reason: %s. Local migration version:%s, Remote migration version:%s\n",
+ incompatible_reason_str[reason], local, remote);
+
+ }
+ return ret;
+
+}
+
+
+char *
+intel_gvt_get_vfio_migration_version(struct intel_gvt *gvt,
+ const char *vgpu_type)
+{
+ int cnt = 0;
+ struct drm_i915_private *dev_priv = gvt->gt->i915;
+ char *version = NULL;
+
+ /* currently only gen8 & gen9 are supported */
+ if (!IS_GEN(dev_priv, 8) && !IS_GEN(dev_priv, 9)) {
+ gvt_err("Local hardware does not support migration on %d\n",
+ INTEL_INFO(dev_priv)->gen);
+ return NULL;
+ }
+
+ if (GVT_VFIO_MIGRATION_SOFTWARE_VERSION == INV_SOFTWARE_VERSION) {
+ gvt_err("Local GVT does not support migration\n");
+ return NULL;
+ }
+
+ version = kzalloc(MIGRATION_VERSION_TOTAL_LEN, GFP_KERNEL);
+
+ if (unlikely(!version)) {
+ gvt_err("cannot allocate memory for local migration version %s\n",
+ vgpu_type);
+ return NULL;
+ }
+
+ /* vendor id + device id + vgpu type + software version */
+ cnt = snprintf(version, MIGRATION_VERSION_TOTAL_LEN, PRINTF_FORMAT,
+ PCI_VENDOR_ID_INTEL,
+ INTEL_DEVID(dev_priv),
+ vgpu_type,
+ GVT_VFIO_MIGRATION_SOFTWARE_VERSION);
+
+ if (cnt)
+ return version;
+
+ gvt_err("cannot generate local migration version for type %s\n",
+ vgpu_type);
+ kfree(version);
+ return NULL;
+}
+
+ssize_t intel_gvt_check_vfio_migration_version(struct intel_gvt *gvt,
+ const char *self, const char *remote)
+{
+ struct drm_i915_private *dev_priv = gvt->gt->i915;
+
+ /* currently only gen8 & gen9 are supported */
+ if (!IS_GEN(dev_priv, 8) && !IS_GEN(dev_priv, 9)) {
+ gvt_err("Local hardware does not support migration on %d\n",
+ INTEL_INFO(dev_priv)->gen);
+ return -ENODEV;
+ }
+
+ if (GVT_VFIO_MIGRATION_SOFTWARE_VERSION == INV_SOFTWARE_VERSION) {
+ gvt_err("Local GVT does not support migration\n");
+ return -ENODEV;
+ }
+
+ if (!is_compatible(self, remote))
+ return -EINVAL;
+
+ return 0;
+}
@@ -155,13 +155,18 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt)
sprintf(gvt->types[i].name, "GVTg_V5_%s",
vgpu_types[i].name);
- gvt_dbg_core("type[%d]: %s avail %u low %u high %u fence %u weight %u res %s\n",
+ gvt->types[i].migration_version =
+ intel_gvt_get_vfio_migration_version(gvt,
+ gvt->types[i].name);
+ gvt_dbg_core("type[%d]: %s avail %u low %u high %u fence %u weight %u res %s, migratio_version:%s\n",
i, gvt->types[i].name,
gvt->types[i].avail_instance,
gvt->types[i].low_gm_size,
gvt->types[i].high_gm_size, gvt->types[i].fence,
gvt->types[i].weight,
- vgpu_edid_str(gvt->types[i].resolution));
+ vgpu_edid_str(gvt->types[i].resolution),
+ (gvt->types[i].migration_version ?
+ gvt->types[i].migration_version : "null"));
}
gvt->num_types = i;
@@ -170,6 +175,10 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt)
void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt)
{
+ int i;
+
+ for (i = 0; i < gvt->num_types; i++)
+ kfree(gvt->types[i].migration_version);
kfree(gvt->types);
}