|
@@ -36,6 +36,8 @@
|
|
|
|
|
|
#include "i915_drv.h"
|
|
|
#include "gvt.h"
|
|
|
+#include <linux/vfio.h>
|
|
|
+#include <linux/mdev.h>
|
|
|
|
|
|
struct intel_gvt_host intel_gvt_host;
|
|
|
|
|
@@ -44,6 +46,129 @@ static const char * const supported_hypervisors[] = {
|
|
|
[INTEL_GVT_HYPERVISOR_KVM] = "KVM",
|
|
|
};
|
|
|
|
|
|
+static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
|
|
|
+ const char *name)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct intel_vgpu_type *t;
|
|
|
+ const char *driver_name = dev_driver_string(
|
|
|
+ &gvt->dev_priv->drm.pdev->dev);
|
|
|
+
|
|
|
+ for (i = 0; i < gvt->num_types; i++) {
|
|
|
+ t = &gvt->types[i];
|
|
|
+ if (!strncmp(t->name, name + strlen(driver_name) + 1,
|
|
|
+ sizeof(t->name)))
|
|
|
+ return t;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t available_instances_show(struct kobject *kobj,
|
|
|
+ struct device *dev, char *buf)
|
|
|
+{
|
|
|
+ struct intel_vgpu_type *type;
|
|
|
+ unsigned int num = 0;
|
|
|
+ void *gvt = kdev_to_i915(dev)->gvt;
|
|
|
+
|
|
|
+ type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
|
|
+ if (!type)
|
|
|
+ num = 0;
|
|
|
+ else
|
|
|
+ num = type->avail_instance;
|
|
|
+
|
|
|
+ return sprintf(buf, "%u\n", num);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t description_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)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
|
|
+ "fence: %d\nresolution: %s\n"
|
|
|
+ "weight: %d\n",
|
|
|
+ BYTES_TO_MB(type->low_gm_size),
|
|
|
+ BYTES_TO_MB(type->high_gm_size),
|
|
|
+ type->fence, vgpu_edid_str(type->resolution),
|
|
|
+ type->weight);
|
|
|
+}
|
|
|
+
|
|
|
+static MDEV_TYPE_ATTR_RO(available_instances);
|
|
|
+static MDEV_TYPE_ATTR_RO(device_api);
|
|
|
+static MDEV_TYPE_ATTR_RO(description);
|
|
|
+
|
|
|
+static struct attribute *gvt_type_attrs[] = {
|
|
|
+ &mdev_type_attr_available_instances.attr,
|
|
|
+ &mdev_type_attr_device_api.attr,
|
|
|
+ &mdev_type_attr_description.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group *gvt_vgpu_type_groups[] = {
|
|
|
+ [0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static bool intel_get_gvt_attrs(struct attribute ***type_attrs,
|
|
|
+ struct attribute_group ***intel_vgpu_type_groups)
|
|
|
+{
|
|
|
+ *type_attrs = gvt_type_attrs;
|
|
|
+ *intel_vgpu_type_groups = gvt_vgpu_type_groups;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
|
|
|
+{
|
|
|
+ int i, j;
|
|
|
+ struct intel_vgpu_type *type;
|
|
|
+ struct attribute_group *group;
|
|
|
+
|
|
|
+ for (i = 0; i < gvt->num_types; i++) {
|
|
|
+ type = &gvt->types[i];
|
|
|
+
|
|
|
+ group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
|
|
|
+ if (WARN_ON(!group))
|
|
|
+ goto unwind;
|
|
|
+
|
|
|
+ group->name = type->name;
|
|
|
+ group->attrs = gvt_type_attrs;
|
|
|
+ gvt_vgpu_type_groups[i] = group;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
+unwind:
|
|
|
+ for (j = 0; j < i; j++) {
|
|
|
+ group = gvt_vgpu_type_groups[j];
|
|
|
+ kfree(group);
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct attribute_group *group;
|
|
|
+
|
|
|
+ for (i = 0; i < gvt->num_types; i++) {
|
|
|
+ group = gvt_vgpu_type_groups[i];
|
|
|
+ gvt_vgpu_type_groups[i] = NULL;
|
|
|
+ kfree(group);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static const struct intel_gvt_ops intel_gvt_ops = {
|
|
|
.emulate_cfg_read = intel_vgpu_emulate_cfg_read,
|
|
|
.emulate_cfg_write = intel_vgpu_emulate_cfg_write,
|
|
@@ -54,6 +179,8 @@ static const struct intel_gvt_ops intel_gvt_ops = {
|
|
|
.vgpu_reset = intel_gvt_reset_vgpu,
|
|
|
.vgpu_activate = intel_gvt_activate_vgpu,
|
|
|
.vgpu_deactivate = intel_gvt_deactivate_vgpu,
|
|
|
+ .gvt_find_vgpu_type = intel_gvt_find_vgpu_type,
|
|
|
+ .get_gvt_attrs = intel_get_gvt_attrs,
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -202,6 +329,7 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
|
|
|
intel_gvt_free_firmware(gvt);
|
|
|
|
|
|
intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev, gvt);
|
|
|
+ intel_gvt_cleanup_vgpu_type_groups(gvt);
|
|
|
intel_gvt_clean_vgpu_types(gvt);
|
|
|
|
|
|
idr_destroy(&gvt->vgpu_idr);
|
|
@@ -292,6 +420,12 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
|
|
|
if (ret)
|
|
|
goto out_clean_thread;
|
|
|
|
|
|
+ ret = intel_gvt_init_vgpu_type_groups(gvt);
|
|
|
+ if (ret == false) {
|
|
|
+ gvt_err("failed to init vgpu type groups: %d\n", ret);
|
|
|
+ goto out_clean_types;
|
|
|
+ }
|
|
|
+
|
|
|
ret = intel_gvt_hypervisor_host_init(&dev_priv->drm.pdev->dev, gvt,
|
|
|
&intel_gvt_ops);
|
|
|
if (ret) {
|