vfio/mdev: simplify mdev_type handling
Instead of abusing struct attribute_group to control initialization of struct mdev_type, just define the actual attributes in the mdev_driver, allocate the mdev_type structures in the caller and pass them to mdev_register_parent. This allows the caller to use container_of to get at the containing structure and thus significantly simplify the code. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Kirti Wankhede <kwankhede@nvidia.com> Reviewed-by: Eric Farman <farman@linux.ibm.com> Link: https://lore.kernel.org/r/20220923092652.100656-6-hch@lst.de Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
89345d5177
commit
da44c340c4
@ -103,7 +103,7 @@ structure to represent a mediated device's driver::
|
|||||||
struct mdev_driver {
|
struct mdev_driver {
|
||||||
int (*probe) (struct mdev_device *dev);
|
int (*probe) (struct mdev_device *dev);
|
||||||
void (*remove) (struct mdev_device *dev);
|
void (*remove) (struct mdev_device *dev);
|
||||||
struct attribute_group **supported_type_groups;
|
const struct attribute * const *types_attrs;
|
||||||
struct device_driver driver;
|
struct device_driver driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,8 +310,8 @@ struct intel_vgpu_config {
|
|||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NR_MAX_INTEL_VGPU_TYPES 20
|
|
||||||
struct intel_vgpu_type {
|
struct intel_vgpu_type {
|
||||||
|
struct mdev_type type;
|
||||||
char name[16];
|
char name[16];
|
||||||
const struct intel_vgpu_config *conf;
|
const struct intel_vgpu_config *conf;
|
||||||
unsigned int avail_instance;
|
unsigned int avail_instance;
|
||||||
@ -339,6 +339,7 @@ struct intel_gvt {
|
|||||||
struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
|
struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
|
||||||
DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
|
DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
|
||||||
struct mdev_parent parent;
|
struct mdev_parent parent;
|
||||||
|
struct mdev_type **mdev_types;
|
||||||
struct intel_vgpu_type *types;
|
struct intel_vgpu_type *types;
|
||||||
unsigned int num_types;
|
unsigned int num_types;
|
||||||
struct intel_vgpu *idle_vgpu;
|
struct intel_vgpu *idle_vgpu;
|
||||||
|
@ -117,17 +117,10 @@ static ssize_t available_instances_show(struct mdev_type *mtype,
|
|||||||
struct mdev_type_attribute *attr,
|
struct mdev_type_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct intel_vgpu_type *type;
|
struct intel_vgpu_type *type =
|
||||||
unsigned int num = 0;
|
container_of(mtype, struct intel_vgpu_type, type);
|
||||||
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
|
||||||
|
|
||||||
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
return sprintf(buf, "%u\n", type->avail_instance);
|
||||||
if (!type)
|
|
||||||
num = 0;
|
|
||||||
else
|
|
||||||
num = type->avail_instance;
|
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t device_api_show(struct mdev_type *mtype,
|
static ssize_t device_api_show(struct mdev_type *mtype,
|
||||||
@ -139,12 +132,8 @@ static ssize_t device_api_show(struct mdev_type *mtype,
|
|||||||
static ssize_t description_show(struct mdev_type *mtype,
|
static ssize_t description_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct intel_vgpu_type *type;
|
struct intel_vgpu_type *type =
|
||||||
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
container_of(mtype, struct intel_vgpu_type, type);
|
||||||
|
|
||||||
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
|
||||||
if (!type)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
||||||
"fence: %d\nresolution: %s\n"
|
"fence: %d\nresolution: %s\n"
|
||||||
@ -158,14 +147,7 @@ static ssize_t description_show(struct mdev_type *mtype,
|
|||||||
static ssize_t name_show(struct mdev_type *mtype,
|
static ssize_t name_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct intel_vgpu_type *type;
|
return sprintf(buf, "%s\n", mtype->sysfs_name);
|
||||||
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
|
||||||
|
|
||||||
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
|
||||||
if (!type)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", type->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MDEV_TYPE_ATTR_RO(available_instances);
|
static MDEV_TYPE_ATTR_RO(available_instances);
|
||||||
@ -173,7 +155,7 @@ static MDEV_TYPE_ATTR_RO(device_api);
|
|||||||
static MDEV_TYPE_ATTR_RO(description);
|
static MDEV_TYPE_ATTR_RO(description);
|
||||||
static MDEV_TYPE_ATTR_RO(name);
|
static MDEV_TYPE_ATTR_RO(name);
|
||||||
|
|
||||||
static struct attribute *gvt_type_attrs[] = {
|
static const struct attribute *gvt_type_attrs[] = {
|
||||||
&mdev_type_attr_available_instances.attr,
|
&mdev_type_attr_available_instances.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
&mdev_type_attr_description.attr,
|
&mdev_type_attr_description.attr,
|
||||||
@ -181,51 +163,6 @@ static struct attribute *gvt_type_attrs[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *gvt_vgpu_type_groups[] = {
|
|
||||||
[0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int 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 (!group)
|
|
||||||
goto unwind;
|
|
||||||
|
|
||||||
group->name = type->name;
|
|
||||||
group->attrs = gvt_type_attrs;
|
|
||||||
gvt_vgpu_type_groups[i] = group;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unwind:
|
|
||||||
for (j = 0; j < i; j++) {
|
|
||||||
group = gvt_vgpu_type_groups[j];
|
|
||||||
kfree(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
||||||
unsigned long size)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
@ -1547,16 +1484,11 @@ static const struct attribute_group *intel_vgpu_groups[] = {
|
|||||||
static int intel_vgpu_init_dev(struct vfio_device *vfio_dev)
|
static int intel_vgpu_init_dev(struct vfio_device *vfio_dev)
|
||||||
{
|
{
|
||||||
struct mdev_device *mdev = to_mdev_device(vfio_dev->dev);
|
struct mdev_device *mdev = to_mdev_device(vfio_dev->dev);
|
||||||
struct device *pdev = mdev_parent_dev(mdev);
|
|
||||||
struct intel_gvt *gvt = kdev_to_i915(pdev)->gvt;
|
|
||||||
struct intel_vgpu_type *type;
|
|
||||||
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
||||||
|
struct intel_vgpu_type *type =
|
||||||
|
container_of(mdev->type, struct intel_vgpu_type, type);
|
||||||
|
|
||||||
type = &gvt->types[mdev_get_type_group_id(mdev)];
|
vgpu->gvt = kdev_to_i915(mdev_parent_dev(mdev))->gvt;
|
||||||
if (!type)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
vgpu->gvt = gvt;
|
|
||||||
return intel_gvt_create_vgpu(vgpu, type->conf);
|
return intel_gvt_create_vgpu(vgpu, type->conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1625,7 +1557,7 @@ static struct mdev_driver intel_vgpu_mdev_driver = {
|
|||||||
},
|
},
|
||||||
.probe = intel_vgpu_probe,
|
.probe = intel_vgpu_probe,
|
||||||
.remove = intel_vgpu_remove,
|
.remove = intel_vgpu_remove,
|
||||||
.supported_type_groups = gvt_vgpu_type_groups,
|
.types_attrs = gvt_type_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn)
|
int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn)
|
||||||
@ -1924,7 +1856,6 @@ static void intel_gvt_clean_device(struct drm_i915_private *i915)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
mdev_unregister_parent(&gvt->parent);
|
mdev_unregister_parent(&gvt->parent);
|
||||||
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
|
||||||
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
||||||
intel_gvt_clean_vgpu_types(gvt);
|
intel_gvt_clean_vgpu_types(gvt);
|
||||||
|
|
||||||
@ -2024,20 +1955,15 @@ static int intel_gvt_init_device(struct drm_i915_private *i915)
|
|||||||
|
|
||||||
intel_gvt_debugfs_init(gvt);
|
intel_gvt_debugfs_init(gvt);
|
||||||
|
|
||||||
ret = intel_gvt_init_vgpu_type_groups(gvt);
|
ret = mdev_register_parent(&gvt->parent, i915->drm.dev,
|
||||||
|
&intel_vgpu_mdev_driver,
|
||||||
|
gvt->mdev_types, gvt->num_types);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_destroy_idle_vgpu;
|
goto out_destroy_idle_vgpu;
|
||||||
|
|
||||||
ret = mdev_register_parent(&gvt->parent, i915->drm.dev,
|
|
||||||
&intel_vgpu_mdev_driver);
|
|
||||||
if (ret)
|
|
||||||
goto out_cleanup_vgpu_type_groups;
|
|
||||||
|
|
||||||
gvt_dbg_core("gvt device initialization is done\n");
|
gvt_dbg_core("gvt device initialization is done\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_cleanup_vgpu_type_groups:
|
|
||||||
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
|
||||||
out_destroy_idle_vgpu:
|
out_destroy_idle_vgpu:
|
||||||
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
||||||
intel_gvt_debugfs_clean(gvt);
|
intel_gvt_debugfs_clean(gvt);
|
||||||
|
@ -113,13 +113,18 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt)
|
|||||||
if (!gvt->types)
|
if (!gvt->types)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gvt->mdev_types = kcalloc(num_types, sizeof(*gvt->mdev_types),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!gvt->mdev_types)
|
||||||
|
goto out_free_types;
|
||||||
|
|
||||||
for (i = 0; i < num_types; ++i) {
|
for (i = 0; i < num_types; ++i) {
|
||||||
const struct intel_vgpu_config *conf = &intel_vgpu_configs[i];
|
const struct intel_vgpu_config *conf = &intel_vgpu_configs[i];
|
||||||
|
|
||||||
if (low_avail / conf->low_mm == 0)
|
if (low_avail / conf->low_mm == 0)
|
||||||
break;
|
break;
|
||||||
if (conf->weight < 1 || conf->weight > VGPU_MAX_WEIGHT)
|
if (conf->weight < 1 || conf->weight > VGPU_MAX_WEIGHT)
|
||||||
goto out_free_types;
|
goto out_free_mdev_types;
|
||||||
|
|
||||||
sprintf(gvt->types[i].name, "GVTg_V%u_%s",
|
sprintf(gvt->types[i].name, "GVTg_V%u_%s",
|
||||||
GRAPHICS_VER(gvt->gt->i915) == 8 ? 4 : 5, conf->name);
|
GRAPHICS_VER(gvt->gt->i915) == 8 ? 4 : 5, conf->name);
|
||||||
@ -131,11 +136,16 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt)
|
|||||||
i, gvt->types[i].name, gvt->types[i].avail_instance,
|
i, gvt->types[i].name, gvt->types[i].avail_instance,
|
||||||
conf->low_mm, conf->high_mm, conf->fence,
|
conf->low_mm, conf->high_mm, conf->fence,
|
||||||
conf->weight, vgpu_edid_str(conf->edid));
|
conf->weight, vgpu_edid_str(conf->edid));
|
||||||
|
|
||||||
|
gvt->mdev_types[i] = &gvt->types[i].type;
|
||||||
|
gvt->mdev_types[i]->sysfs_name = gvt->types[i].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
gvt->num_types = i;
|
gvt->num_types = i;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_free_mdev_types:
|
||||||
|
kfree(gvt->mdev_types);
|
||||||
out_free_types:
|
out_free_types:
|
||||||
kfree(gvt->types);
|
kfree(gvt->types);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -143,6 +153,7 @@ out_free_types:
|
|||||||
|
|
||||||
void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt)
|
void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt)
|
||||||
{
|
{
|
||||||
|
kfree(gvt->mdev_types);
|
||||||
kfree(gvt->types);
|
kfree(gvt->types);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,6 @@ static void vfio_ccw_free_private(struct vfio_ccw_private *private)
|
|||||||
mutex_destroy(&private->io_mutex);
|
mutex_destroy(&private->io_mutex);
|
||||||
kfree(private);
|
kfree(private);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vfio_ccw_sch_probe(struct subchannel *sch)
|
static int vfio_ccw_sch_probe(struct subchannel *sch)
|
||||||
{
|
{
|
||||||
struct pmcw *pmcw = &sch->schib.pmcw;
|
struct pmcw *pmcw = &sch->schib.pmcw;
|
||||||
@ -221,8 +220,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
|
|||||||
|
|
||||||
dev_set_drvdata(&sch->dev, private);
|
dev_set_drvdata(&sch->dev, private);
|
||||||
|
|
||||||
|
private->mdev_type.sysfs_name = "io";
|
||||||
|
private->mdev_types[0] = &private->mdev_type;
|
||||||
ret = mdev_register_parent(&private->parent, &sch->dev,
|
ret = mdev_register_parent(&private->parent, &sch->dev,
|
||||||
&vfio_ccw_mdev_driver);
|
&vfio_ccw_mdev_driver,
|
||||||
|
private->mdev_types, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
|
@ -69,23 +69,13 @@ static ssize_t available_instances_show(struct mdev_type *mtype,
|
|||||||
}
|
}
|
||||||
static MDEV_TYPE_ATTR_RO(available_instances);
|
static MDEV_TYPE_ATTR_RO(available_instances);
|
||||||
|
|
||||||
static struct attribute *mdev_types_attrs[] = {
|
static const struct attribute *mdev_types_attrs[] = {
|
||||||
&mdev_type_attr_name.attr,
|
&mdev_type_attr_name.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
&mdev_type_attr_available_instances.attr,
|
&mdev_type_attr_available_instances.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group = {
|
|
||||||
.name = "io",
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group *mdev_type_groups[] = {
|
|
||||||
&mdev_type_group,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
|
static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
|
||||||
{
|
{
|
||||||
struct vfio_ccw_private *private =
|
struct vfio_ccw_private *private =
|
||||||
@ -646,5 +636,5 @@ struct mdev_driver vfio_ccw_mdev_driver = {
|
|||||||
},
|
},
|
||||||
.probe = vfio_ccw_mdev_probe,
|
.probe = vfio_ccw_mdev_probe,
|
||||||
.remove = vfio_ccw_mdev_remove,
|
.remove = vfio_ccw_mdev_remove,
|
||||||
.supported_type_groups = mdev_type_groups,
|
.types_attrs = mdev_types_attrs,
|
||||||
};
|
};
|
||||||
|
@ -120,6 +120,8 @@ struct vfio_ccw_private {
|
|||||||
struct completion release_comp;
|
struct completion release_comp;
|
||||||
|
|
||||||
struct mdev_parent parent;
|
struct mdev_parent parent;
|
||||||
|
struct mdev_type mdev_type;
|
||||||
|
struct mdev_type *mdev_types[1];
|
||||||
} __aligned(8);
|
} __aligned(8);
|
||||||
|
|
||||||
int vfio_ccw_sch_quiesce(struct subchannel *sch);
|
int vfio_ccw_sch_quiesce(struct subchannel *sch);
|
||||||
|
@ -816,23 +816,13 @@ static ssize_t device_api_show(struct mdev_type *mtype,
|
|||||||
|
|
||||||
static MDEV_TYPE_ATTR_RO(device_api);
|
static MDEV_TYPE_ATTR_RO(device_api);
|
||||||
|
|
||||||
static struct attribute *vfio_ap_mdev_type_attrs[] = {
|
static const struct attribute *vfio_ap_mdev_type_attrs[] = {
|
||||||
&mdev_type_attr_name.attr,
|
&mdev_type_attr_name.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
&mdev_type_attr_available_instances.attr,
|
&mdev_type_attr_available_instances.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group vfio_ap_mdev_hwvirt_type_group = {
|
|
||||||
.name = VFIO_AP_MDEV_TYPE_HWVIRT,
|
|
||||||
.attrs = vfio_ap_mdev_type_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group *vfio_ap_mdev_type_groups[] = {
|
|
||||||
&vfio_ap_mdev_hwvirt_type_group,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \
|
#define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \
|
||||||
"already assigned to %s"
|
"already assigned to %s"
|
||||||
|
|
||||||
@ -1817,7 +1807,7 @@ static struct mdev_driver vfio_ap_matrix_driver = {
|
|||||||
},
|
},
|
||||||
.probe = vfio_ap_mdev_probe,
|
.probe = vfio_ap_mdev_probe,
|
||||||
.remove = vfio_ap_mdev_remove,
|
.remove = vfio_ap_mdev_remove,
|
||||||
.supported_type_groups = vfio_ap_mdev_type_groups,
|
.types_attrs = vfio_ap_mdev_type_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
int vfio_ap_mdev_register(void)
|
int vfio_ap_mdev_register(void)
|
||||||
@ -1830,8 +1820,11 @@ int vfio_ap_mdev_register(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
matrix_dev->mdev_type.sysfs_name = VFIO_AP_MDEV_TYPE_HWVIRT;
|
||||||
|
matrix_dev->mdev_types[0] = &matrix_dev->mdev_type;
|
||||||
ret = mdev_register_parent(&matrix_dev->parent, &matrix_dev->device,
|
ret = mdev_register_parent(&matrix_dev->parent, &matrix_dev->device,
|
||||||
&vfio_ap_matrix_driver);
|
&vfio_ap_matrix_driver,
|
||||||
|
matrix_dev->mdev_types, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_driver;
|
goto err_driver;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -53,6 +53,8 @@ struct ap_matrix_dev {
|
|||||||
struct ap_driver *vfio_ap_drv;
|
struct ap_driver *vfio_ap_drv;
|
||||||
struct mutex guests_lock; /* serializes access to each KVM guest */
|
struct mutex guests_lock; /* serializes access to each KVM guest */
|
||||||
struct mdev_parent parent;
|
struct mdev_parent parent;
|
||||||
|
struct mdev_type mdev_type;
|
||||||
|
struct mdev_type *mdev_types[];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct ap_matrix_dev *matrix_dev;
|
extern struct ap_matrix_dev *matrix_dev;
|
||||||
|
@ -29,26 +29,6 @@ struct device *mdev_parent_dev(struct mdev_device *mdev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mdev_parent_dev);
|
EXPORT_SYMBOL(mdev_parent_dev);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the index in supported_type_groups that this mdev_device was created
|
|
||||||
* from.
|
|
||||||
*/
|
|
||||||
unsigned int mdev_get_type_group_id(struct mdev_device *mdev)
|
|
||||||
{
|
|
||||||
return mdev->type->type_group_id;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(mdev_get_type_group_id);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used in mdev_type_attribute sysfs functions to return the index in the
|
|
||||||
* supported_type_groups that the sysfs is called from.
|
|
||||||
*/
|
|
||||||
unsigned int mtype_get_type_group_id(struct mdev_type *mtype)
|
|
||||||
{
|
|
||||||
return mtype->type_group_id;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(mtype_get_type_group_id);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used in mdev_type_attribute sysfs functions to return the parent struct
|
* Used in mdev_type_attribute sysfs functions to return the parent struct
|
||||||
* device
|
* device
|
||||||
@ -85,6 +65,8 @@ static int mdev_device_remove_cb(struct device *dev, void *data)
|
|||||||
* @parent: parent structure registered
|
* @parent: parent structure registered
|
||||||
* @dev: device structure representing parent device.
|
* @dev: device structure representing parent device.
|
||||||
* @mdev_driver: Device driver to bind to the newly created mdev
|
* @mdev_driver: Device driver to bind to the newly created mdev
|
||||||
|
* @types: Array of supported mdev types
|
||||||
|
* @nr_types: Number of entries in @types
|
||||||
*
|
*
|
||||||
* Registers the @parent stucture as a parent for mdev types and thus mdev
|
* Registers the @parent stucture as a parent for mdev types and thus mdev
|
||||||
* devices. The caller needs to hold a reference on @dev that must not be
|
* devices. The caller needs to hold a reference on @dev that must not be
|
||||||
@ -93,20 +75,19 @@ static int mdev_device_remove_cb(struct device *dev, void *data)
|
|||||||
* Returns a negative value on error, otherwise 0.
|
* Returns a negative value on error, otherwise 0.
|
||||||
*/
|
*/
|
||||||
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
|
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
|
||||||
struct mdev_driver *mdev_driver)
|
struct mdev_driver *mdev_driver, struct mdev_type **types,
|
||||||
|
unsigned int nr_types)
|
||||||
{
|
{
|
||||||
char *env_string = "MDEV_STATE=registered";
|
char *env_string = "MDEV_STATE=registered";
|
||||||
char *envp[] = { env_string, NULL };
|
char *envp[] = { env_string, NULL };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* check for mandatory ops */
|
|
||||||
if (!mdev_driver->supported_type_groups)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(parent, 0, sizeof(*parent));
|
memset(parent, 0, sizeof(*parent));
|
||||||
init_rwsem(&parent->unreg_sem);
|
init_rwsem(&parent->unreg_sem);
|
||||||
parent->dev = dev;
|
parent->dev = dev;
|
||||||
parent->mdev_driver = mdev_driver;
|
parent->mdev_driver = mdev_driver;
|
||||||
|
parent->types = types;
|
||||||
|
parent->nr_types = nr_types;
|
||||||
|
|
||||||
if (!mdev_bus_compat_class) {
|
if (!mdev_bus_compat_class) {
|
||||||
mdev_bus_compat_class = class_compat_register("mdev_bus");
|
mdev_bus_compat_class = class_compat_register("mdev_bus");
|
||||||
|
@ -56,10 +56,9 @@ EXPORT_SYMBOL_GPL(mdev_bus_type);
|
|||||||
**/
|
**/
|
||||||
int mdev_register_driver(struct mdev_driver *drv)
|
int mdev_register_driver(struct mdev_driver *drv)
|
||||||
{
|
{
|
||||||
/* initialize common driver fields */
|
if (!drv->types_attrs)
|
||||||
|
return -EINVAL;
|
||||||
drv->driver.bus = &mdev_bus_type;
|
drv->driver.bus = &mdev_bus_type;
|
||||||
|
|
||||||
/* register with core */
|
|
||||||
return driver_register(&drv->driver);
|
return driver_register(&drv->driver);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mdev_register_driver);
|
EXPORT_SYMBOL(mdev_register_driver);
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
int mdev_bus_register(void);
|
int mdev_bus_register(void);
|
||||||
void mdev_bus_unregister(void);
|
void mdev_bus_unregister(void);
|
||||||
|
|
||||||
struct mdev_type {
|
|
||||||
struct kobject kobj;
|
|
||||||
struct kobject *devices_kobj;
|
|
||||||
struct mdev_parent *parent;
|
|
||||||
struct list_head next;
|
|
||||||
unsigned int type_group_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const struct attribute_group *mdev_device_groups[];
|
extern const struct attribute_group *mdev_device_groups[];
|
||||||
|
|
||||||
#define to_mdev_type_attr(_attr) \
|
#define to_mdev_type_attr(_attr) \
|
||||||
|
@ -82,7 +82,6 @@ static void mdev_type_release(struct kobject *kobj)
|
|||||||
pr_debug("Releasing group %s\n", kobj->name);
|
pr_debug("Releasing group %s\n", kobj->name);
|
||||||
/* Pairs with the get in add_mdev_supported_type() */
|
/* Pairs with the get in add_mdev_supported_type() */
|
||||||
put_device(type->parent->dev);
|
put_device(type->parent->dev);
|
||||||
kfree(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kobj_type mdev_type_ktype = {
|
static struct kobj_type mdev_type_ktype = {
|
||||||
@ -90,35 +89,21 @@ static struct kobj_type mdev_type_ktype = {
|
|||||||
.release = mdev_type_release,
|
.release = mdev_type_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
|
static int mdev_type_add(struct mdev_parent *parent, struct mdev_type *type)
|
||||||
unsigned int type_group_id)
|
|
||||||
{
|
{
|
||||||
struct mdev_type *type;
|
|
||||||
struct attribute_group *group =
|
|
||||||
parent->mdev_driver->supported_type_groups[type_group_id];
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!group->name) {
|
|
||||||
pr_err("%s: Type name empty!\n", __func__);
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
type = kzalloc(sizeof(*type), GFP_KERNEL);
|
|
||||||
if (!type)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
type->kobj.kset = parent->mdev_types_kset;
|
type->kobj.kset = parent->mdev_types_kset;
|
||||||
type->parent = parent;
|
type->parent = parent;
|
||||||
/* Pairs with the put in mdev_type_release() */
|
/* Pairs with the put in mdev_type_release() */
|
||||||
get_device(parent->dev);
|
get_device(parent->dev);
|
||||||
type->type_group_id = type_group_id;
|
|
||||||
|
|
||||||
ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
|
ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
|
||||||
"%s-%s", dev_driver_string(parent->dev),
|
"%s-%s", dev_driver_string(parent->dev),
|
||||||
group->name);
|
type->sysfs_name);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kobject_put(&type->kobj);
|
kobject_put(&type->kobj);
|
||||||
return ERR_PTR(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
|
ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr);
|
||||||
@ -131,13 +116,10 @@ static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
|
|||||||
goto attr_devices_failed;
|
goto attr_devices_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sysfs_create_files(&type->kobj,
|
ret = sysfs_create_files(&type->kobj, parent->mdev_driver->types_attrs);
|
||||||
(const struct attribute **)group->attrs);
|
if (ret)
|
||||||
if (ret) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto attrs_failed;
|
goto attrs_failed;
|
||||||
}
|
return 0;
|
||||||
return type;
|
|
||||||
|
|
||||||
attrs_failed:
|
attrs_failed:
|
||||||
kobject_put(type->devices_kobj);
|
kobject_put(type->devices_kobj);
|
||||||
@ -146,78 +128,49 @@ attr_devices_failed:
|
|||||||
attr_create_failed:
|
attr_create_failed:
|
||||||
kobject_del(&type->kobj);
|
kobject_del(&type->kobj);
|
||||||
kobject_put(&type->kobj);
|
kobject_put(&type->kobj);
|
||||||
return ERR_PTR(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_mdev_supported_type(struct mdev_type *type)
|
static void mdev_type_remove(struct mdev_type *type)
|
||||||
{
|
{
|
||||||
struct attribute_group *group =
|
sysfs_remove_files(&type->kobj, type->parent->mdev_driver->types_attrs);
|
||||||
type->parent->mdev_driver->supported_type_groups[type->type_group_id];
|
|
||||||
|
|
||||||
sysfs_remove_files(&type->kobj,
|
|
||||||
(const struct attribute **)group->attrs);
|
|
||||||
kobject_put(type->devices_kobj);
|
kobject_put(type->devices_kobj);
|
||||||
sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
|
sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr);
|
||||||
kobject_del(&type->kobj);
|
kobject_del(&type->kobj);
|
||||||
kobject_put(&type->kobj);
|
kobject_put(&type->kobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_mdev_supported_type_groups(struct mdev_parent *parent)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; parent->mdev_driver->supported_type_groups[i]; i++) {
|
|
||||||
struct mdev_type *type;
|
|
||||||
|
|
||||||
type = add_mdev_supported_type(parent, i);
|
|
||||||
if (IS_ERR(type)) {
|
|
||||||
struct mdev_type *ltype, *tmp;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(ltype, tmp, &parent->type_list,
|
|
||||||
next) {
|
|
||||||
list_del(<ype->next);
|
|
||||||
remove_mdev_supported_type(ltype);
|
|
||||||
}
|
|
||||||
return PTR_ERR(type);
|
|
||||||
}
|
|
||||||
list_add(&type->next, &parent->type_list);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mdev sysfs functions */
|
/* mdev sysfs functions */
|
||||||
void parent_remove_sysfs_files(struct mdev_parent *parent)
|
void parent_remove_sysfs_files(struct mdev_parent *parent)
|
||||||
{
|
{
|
||||||
struct mdev_type *type, *tmp;
|
int i;
|
||||||
|
|
||||||
list_for_each_entry_safe(type, tmp, &parent->type_list, next) {
|
|
||||||
list_del(&type->next);
|
|
||||||
remove_mdev_supported_type(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (i = 0; i < parent->nr_types; i++)
|
||||||
|
mdev_type_remove(parent->types[i]);
|
||||||
kset_unregister(parent->mdev_types_kset);
|
kset_unregister(parent->mdev_types_kset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int parent_create_sysfs_files(struct mdev_parent *parent)
|
int parent_create_sysfs_files(struct mdev_parent *parent)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, i;
|
||||||
|
|
||||||
parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
|
parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
|
||||||
NULL, &parent->dev->kobj);
|
NULL, &parent->dev->kobj);
|
||||||
|
|
||||||
if (!parent->mdev_types_kset)
|
if (!parent->mdev_types_kset)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&parent->type_list);
|
for (i = 0; i < parent->nr_types; i++) {
|
||||||
|
ret = mdev_type_add(parent, parent->types[i]);
|
||||||
ret = add_mdev_supported_type_groups(parent);
|
if (ret)
|
||||||
if (ret)
|
goto out_err;
|
||||||
goto create_err;
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
create_err:
|
out_err:
|
||||||
kset_unregister(parent->mdev_types_kset);
|
while (--i >= 0)
|
||||||
return ret;
|
mdev_type_remove(parent->types[i]);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
@ -23,14 +23,27 @@ struct mdev_device {
|
|||||||
bool active;
|
bool active;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mdev_type {
|
||||||
|
/* set by the driver before calling mdev_register parent: */
|
||||||
|
const char *sysfs_name;
|
||||||
|
|
||||||
|
/* set by the core, can be used drivers */
|
||||||
|
struct mdev_parent *parent;
|
||||||
|
|
||||||
|
/* internal only */
|
||||||
|
struct kobject kobj;
|
||||||
|
struct kobject *devices_kobj;
|
||||||
|
};
|
||||||
|
|
||||||
/* embedded into the struct device that the mdev devices hang off */
|
/* embedded into the struct device that the mdev devices hang off */
|
||||||
struct mdev_parent {
|
struct mdev_parent {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct mdev_driver *mdev_driver;
|
struct mdev_driver *mdev_driver;
|
||||||
struct kset *mdev_types_kset;
|
struct kset *mdev_types_kset;
|
||||||
struct list_head type_list;
|
|
||||||
/* Synchronize device creation/removal with parent unregistration */
|
/* Synchronize device creation/removal with parent unregistration */
|
||||||
struct rw_semaphore unreg_sem;
|
struct rw_semaphore unreg_sem;
|
||||||
|
struct mdev_type **types;
|
||||||
|
unsigned int nr_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct mdev_device *to_mdev_device(struct device *dev)
|
static inline struct mdev_device *to_mdev_device(struct device *dev)
|
||||||
@ -38,8 +51,6 @@ static inline struct mdev_device *to_mdev_device(struct device *dev)
|
|||||||
return container_of(dev, struct mdev_device, dev);
|
return container_of(dev, struct mdev_device, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int mdev_get_type_group_id(struct mdev_device *mdev);
|
|
||||||
unsigned int mtype_get_type_group_id(struct mdev_type *mtype);
|
|
||||||
struct device *mtype_get_parent_dev(struct mdev_type *mtype);
|
struct device *mtype_get_parent_dev(struct mdev_type *mtype);
|
||||||
|
|
||||||
/* interface for exporting mdev supported type attributes */
|
/* interface for exporting mdev supported type attributes */
|
||||||
@ -66,22 +77,21 @@ struct mdev_type_attribute mdev_type_attr_##_name = \
|
|||||||
* struct mdev_driver - Mediated device driver
|
* struct mdev_driver - Mediated device driver
|
||||||
* @probe: called when new device created
|
* @probe: called when new device created
|
||||||
* @remove: called when device removed
|
* @remove: called when device removed
|
||||||
* @supported_type_groups: Attributes to define supported types. It is mandatory
|
* @types_attrs: attributes to the type kobjects.
|
||||||
* to provide supported types.
|
|
||||||
* @driver: device driver structure
|
* @driver: device driver structure
|
||||||
*
|
|
||||||
**/
|
**/
|
||||||
struct mdev_driver {
|
struct mdev_driver {
|
||||||
int (*probe)(struct mdev_device *dev);
|
int (*probe)(struct mdev_device *dev);
|
||||||
void (*remove)(struct mdev_device *dev);
|
void (*remove)(struct mdev_device *dev);
|
||||||
struct attribute_group **supported_type_groups;
|
const struct attribute * const *types_attrs;
|
||||||
struct device_driver driver;
|
struct device_driver driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct bus_type mdev_bus_type;
|
extern struct bus_type mdev_bus_type;
|
||||||
|
|
||||||
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
|
int mdev_register_parent(struct mdev_parent *parent, struct device *dev,
|
||||||
struct mdev_driver *mdev_driver);
|
struct mdev_driver *mdev_driver, struct mdev_type **types,
|
||||||
|
unsigned int nr_types);
|
||||||
void mdev_unregister_parent(struct mdev_parent *parent);
|
void mdev_unregister_parent(struct mdev_parent *parent);
|
||||||
|
|
||||||
int mdev_register_driver(struct mdev_driver *drv);
|
int mdev_register_driver(struct mdev_driver *drv);
|
||||||
|
@ -99,23 +99,27 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices");
|
|||||||
#define MBOCHS_TYPE_2 "medium"
|
#define MBOCHS_TYPE_2 "medium"
|
||||||
#define MBOCHS_TYPE_3 "large"
|
#define MBOCHS_TYPE_3 "large"
|
||||||
|
|
||||||
static const struct mbochs_type {
|
static struct mbochs_type {
|
||||||
|
struct mdev_type type;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 mbytes;
|
u32 mbytes;
|
||||||
u32 max_x;
|
u32 max_x;
|
||||||
u32 max_y;
|
u32 max_y;
|
||||||
} mbochs_types[] = {
|
} mbochs_types[] = {
|
||||||
{
|
{
|
||||||
|
.type.sysfs_name = MBOCHS_TYPE_1,
|
||||||
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1,
|
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1,
|
||||||
.mbytes = 4,
|
.mbytes = 4,
|
||||||
.max_x = 800,
|
.max_x = 800,
|
||||||
.max_y = 600,
|
.max_y = 600,
|
||||||
}, {
|
}, {
|
||||||
|
.type.sysfs_name = MBOCHS_TYPE_2,
|
||||||
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2,
|
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2,
|
||||||
.mbytes = 16,
|
.mbytes = 16,
|
||||||
.max_x = 1920,
|
.max_x = 1920,
|
||||||
.max_y = 1440,
|
.max_y = 1440,
|
||||||
}, {
|
}, {
|
||||||
|
.type.sysfs_name = MBOCHS_TYPE_3,
|
||||||
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3,
|
.name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3,
|
||||||
.mbytes = 64,
|
.mbytes = 64,
|
||||||
.max_x = 0,
|
.max_x = 0,
|
||||||
@ -123,6 +127,11 @@ static const struct mbochs_type {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mdev_type *mbochs_mdev_types[] = {
|
||||||
|
&mbochs_types[0].type,
|
||||||
|
&mbochs_types[1].type,
|
||||||
|
&mbochs_types[2].type,
|
||||||
|
};
|
||||||
|
|
||||||
static dev_t mbochs_devt;
|
static dev_t mbochs_devt;
|
||||||
static struct class *mbochs_class;
|
static struct class *mbochs_class;
|
||||||
@ -510,8 +519,8 @@ static int mbochs_init_dev(struct vfio_device *vdev)
|
|||||||
struct mdev_state *mdev_state =
|
struct mdev_state *mdev_state =
|
||||||
container_of(vdev, struct mdev_state, vdev);
|
container_of(vdev, struct mdev_state, vdev);
|
||||||
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
||||||
const struct mbochs_type *type =
|
struct mbochs_type *type =
|
||||||
&mbochs_types[mdev_get_type_group_id(mdev)];
|
container_of(mdev->type, struct mbochs_type, type);
|
||||||
int avail_mbytes = atomic_read(&mbochs_avail_mbytes);
|
int avail_mbytes = atomic_read(&mbochs_avail_mbytes);
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
@ -1345,8 +1354,8 @@ static const struct attribute_group *mdev_dev_groups[] = {
|
|||||||
static ssize_t name_show(struct mdev_type *mtype,
|
static ssize_t name_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
const struct mbochs_type *type =
|
struct mbochs_type *type =
|
||||||
&mbochs_types[mtype_get_type_group_id(mtype)];
|
container_of(mtype, struct mbochs_type, type);
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", type->name);
|
return sprintf(buf, "%s\n", type->name);
|
||||||
}
|
}
|
||||||
@ -1355,8 +1364,8 @@ static MDEV_TYPE_ATTR_RO(name);
|
|||||||
static ssize_t description_show(struct mdev_type *mtype,
|
static ssize_t description_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
const struct mbochs_type *type =
|
struct mbochs_type *type =
|
||||||
&mbochs_types[mtype_get_type_group_id(mtype)];
|
container_of(mtype, struct mbochs_type, type);
|
||||||
|
|
||||||
return sprintf(buf, "virtual display, %d MB video memory\n",
|
return sprintf(buf, "virtual display, %d MB video memory\n",
|
||||||
type ? type->mbytes : 0);
|
type ? type->mbytes : 0);
|
||||||
@ -1367,8 +1376,8 @@ static ssize_t available_instances_show(struct mdev_type *mtype,
|
|||||||
struct mdev_type_attribute *attr,
|
struct mdev_type_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
const struct mbochs_type *type =
|
struct mbochs_type *type =
|
||||||
&mbochs_types[mtype_get_type_group_id(mtype)];
|
container_of(mtype, struct mbochs_type, type);
|
||||||
int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes;
|
int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", count);
|
return sprintf(buf, "%d\n", count);
|
||||||
@ -1382,7 +1391,7 @@ static ssize_t device_api_show(struct mdev_type *mtype,
|
|||||||
}
|
}
|
||||||
static MDEV_TYPE_ATTR_RO(device_api);
|
static MDEV_TYPE_ATTR_RO(device_api);
|
||||||
|
|
||||||
static struct attribute *mdev_types_attrs[] = {
|
static const struct attribute *mdev_types_attrs[] = {
|
||||||
&mdev_type_attr_name.attr,
|
&mdev_type_attr_name.attr,
|
||||||
&mdev_type_attr_description.attr,
|
&mdev_type_attr_description.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
@ -1390,28 +1399,6 @@ static struct attribute *mdev_types_attrs[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group1 = {
|
|
||||||
.name = MBOCHS_TYPE_1,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group2 = {
|
|
||||||
.name = MBOCHS_TYPE_2,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group3 = {
|
|
||||||
.name = MBOCHS_TYPE_3,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group *mdev_type_groups[] = {
|
|
||||||
&mdev_type_group1,
|
|
||||||
&mdev_type_group2,
|
|
||||||
&mdev_type_group3,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct vfio_device_ops mbochs_dev_ops = {
|
static const struct vfio_device_ops mbochs_dev_ops = {
|
||||||
.close_device = mbochs_close_device,
|
.close_device = mbochs_close_device,
|
||||||
.init = mbochs_init_dev,
|
.init = mbochs_init_dev,
|
||||||
@ -1431,7 +1418,7 @@ static struct mdev_driver mbochs_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mbochs_probe,
|
.probe = mbochs_probe,
|
||||||
.remove = mbochs_remove,
|
.remove = mbochs_remove,
|
||||||
.supported_type_groups = mdev_type_groups,
|
.types_attrs = mdev_types_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations vd_fops = {
|
static const struct file_operations vd_fops = {
|
||||||
@ -1476,7 +1463,9 @@ static int __init mbochs_dev_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver);
|
ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver,
|
||||||
|
mbochs_mdev_types,
|
||||||
|
ARRAY_SIZE(mbochs_mdev_types));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
|
|
||||||
|
@ -51,7 +51,8 @@ MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices");
|
|||||||
#define MDPY_TYPE_2 "xga"
|
#define MDPY_TYPE_2 "xga"
|
||||||
#define MDPY_TYPE_3 "hd"
|
#define MDPY_TYPE_3 "hd"
|
||||||
|
|
||||||
static const struct mdpy_type {
|
static struct mdpy_type {
|
||||||
|
struct mdev_type type;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 format;
|
u32 format;
|
||||||
u32 bytepp;
|
u32 bytepp;
|
||||||
@ -59,18 +60,21 @@ static const struct mdpy_type {
|
|||||||
u32 height;
|
u32 height;
|
||||||
} mdpy_types[] = {
|
} mdpy_types[] = {
|
||||||
{
|
{
|
||||||
|
.type.sysfs_name = MDPY_TYPE_1,
|
||||||
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_1,
|
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_1,
|
||||||
.format = DRM_FORMAT_XRGB8888,
|
.format = DRM_FORMAT_XRGB8888,
|
||||||
.bytepp = 4,
|
.bytepp = 4,
|
||||||
.width = 640,
|
.width = 640,
|
||||||
.height = 480,
|
.height = 480,
|
||||||
}, {
|
}, {
|
||||||
|
.type.sysfs_name = MDPY_TYPE_2,
|
||||||
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_2,
|
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_2,
|
||||||
.format = DRM_FORMAT_XRGB8888,
|
.format = DRM_FORMAT_XRGB8888,
|
||||||
.bytepp = 4,
|
.bytepp = 4,
|
||||||
.width = 1024,
|
.width = 1024,
|
||||||
.height = 768,
|
.height = 768,
|
||||||
}, {
|
}, {
|
||||||
|
.type.sysfs_name = MDPY_TYPE_3,
|
||||||
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_3,
|
.name = MDPY_CLASS_NAME "-" MDPY_TYPE_3,
|
||||||
.format = DRM_FORMAT_XRGB8888,
|
.format = DRM_FORMAT_XRGB8888,
|
||||||
.bytepp = 4,
|
.bytepp = 4,
|
||||||
@ -79,6 +83,12 @@ static const struct mdpy_type {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mdev_type *mdpy_mdev_types[] = {
|
||||||
|
&mdpy_types[0].type,
|
||||||
|
&mdpy_types[1].type,
|
||||||
|
&mdpy_types[2].type,
|
||||||
|
};
|
||||||
|
|
||||||
static dev_t mdpy_devt;
|
static dev_t mdpy_devt;
|
||||||
static struct class *mdpy_class;
|
static struct class *mdpy_class;
|
||||||
static struct cdev mdpy_cdev;
|
static struct cdev mdpy_cdev;
|
||||||
@ -222,7 +232,7 @@ static int mdpy_init_dev(struct vfio_device *vdev)
|
|||||||
container_of(vdev, struct mdev_state, vdev);
|
container_of(vdev, struct mdev_state, vdev);
|
||||||
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
||||||
const struct mdpy_type *type =
|
const struct mdpy_type *type =
|
||||||
&mdpy_types[mdev_get_type_group_id(mdev)];
|
container_of(mdev->type, struct mdpy_type, type);
|
||||||
u32 fbsize;
|
u32 fbsize;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
@ -655,8 +665,7 @@ static const struct attribute_group *mdev_dev_groups[] = {
|
|||||||
static ssize_t name_show(struct mdev_type *mtype,
|
static ssize_t name_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
const struct mdpy_type *type =
|
struct mdpy_type *type = container_of(mtype, struct mdpy_type, type);
|
||||||
&mdpy_types[mtype_get_type_group_id(mtype)];
|
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", type->name);
|
return sprintf(buf, "%s\n", type->name);
|
||||||
}
|
}
|
||||||
@ -665,8 +674,7 @@ static MDEV_TYPE_ATTR_RO(name);
|
|||||||
static ssize_t description_show(struct mdev_type *mtype,
|
static ssize_t description_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
const struct mdpy_type *type =
|
struct mdpy_type *type = container_of(mtype, struct mdpy_type, type);
|
||||||
&mdpy_types[mtype_get_type_group_id(mtype)];
|
|
||||||
|
|
||||||
return sprintf(buf, "virtual display, %dx%d framebuffer\n",
|
return sprintf(buf, "virtual display, %dx%d framebuffer\n",
|
||||||
type->width, type->height);
|
type->width, type->height);
|
||||||
@ -688,7 +696,7 @@ static ssize_t device_api_show(struct mdev_type *mtype,
|
|||||||
}
|
}
|
||||||
static MDEV_TYPE_ATTR_RO(device_api);
|
static MDEV_TYPE_ATTR_RO(device_api);
|
||||||
|
|
||||||
static struct attribute *mdev_types_attrs[] = {
|
static const struct attribute *mdev_types_attrs[] = {
|
||||||
&mdev_type_attr_name.attr,
|
&mdev_type_attr_name.attr,
|
||||||
&mdev_type_attr_description.attr,
|
&mdev_type_attr_description.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
@ -696,28 +704,6 @@ static struct attribute *mdev_types_attrs[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group1 = {
|
|
||||||
.name = MDPY_TYPE_1,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group2 = {
|
|
||||||
.name = MDPY_TYPE_2,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group3 = {
|
|
||||||
.name = MDPY_TYPE_3,
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group *mdev_type_groups[] = {
|
|
||||||
&mdev_type_group1,
|
|
||||||
&mdev_type_group2,
|
|
||||||
&mdev_type_group3,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct vfio_device_ops mdpy_dev_ops = {
|
static const struct vfio_device_ops mdpy_dev_ops = {
|
||||||
.init = mdpy_init_dev,
|
.init = mdpy_init_dev,
|
||||||
.release = mdpy_release_dev,
|
.release = mdpy_release_dev,
|
||||||
@ -736,7 +722,7 @@ static struct mdev_driver mdpy_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mdpy_probe,
|
.probe = mdpy_probe,
|
||||||
.remove = mdpy_remove,
|
.remove = mdpy_remove,
|
||||||
.supported_type_groups = mdev_type_groups,
|
.types_attrs = mdev_types_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations vd_fops = {
|
static const struct file_operations vd_fops = {
|
||||||
@ -779,7 +765,9 @@ static int __init mdpy_dev_init(void)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver);
|
ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver,
|
||||||
|
mdpy_mdev_types,
|
||||||
|
ARRAY_SIZE(mdpy_mdev_types));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
|
|
||||||
|
@ -143,6 +143,20 @@ struct mdev_state {
|
|||||||
int nr_ports;
|
int nr_ports;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mtty_type {
|
||||||
|
struct mdev_type type;
|
||||||
|
int nr_ports;
|
||||||
|
const char *name;
|
||||||
|
} mtty_types[2] = {
|
||||||
|
{ .nr_ports = 1, .type.sysfs_name = "1", .name = "Single port serial" },
|
||||||
|
{ .nr_ports = 2, .type.sysfs_name = "2", .name = "Dual port serial" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mdev_type *mtty_mdev_types[] = {
|
||||||
|
&mtty_types[0].type,
|
||||||
|
&mtty_types[1].type,
|
||||||
|
};
|
||||||
|
|
||||||
static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS);
|
static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS);
|
||||||
|
|
||||||
static const struct file_operations vd_fops = {
|
static const struct file_operations vd_fops = {
|
||||||
@ -707,17 +721,19 @@ static int mtty_init_dev(struct vfio_device *vdev)
|
|||||||
struct mdev_state *mdev_state =
|
struct mdev_state *mdev_state =
|
||||||
container_of(vdev, struct mdev_state, vdev);
|
container_of(vdev, struct mdev_state, vdev);
|
||||||
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
struct mdev_device *mdev = to_mdev_device(vdev->dev);
|
||||||
int nr_ports = mdev_get_type_group_id(mdev) + 1;
|
struct mtty_type *type =
|
||||||
|
container_of(mdev->type, struct mtty_type, type);
|
||||||
int avail_ports = atomic_read(&mdev_avail_ports);
|
int avail_ports = atomic_read(&mdev_avail_ports);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (avail_ports < nr_ports)
|
if (avail_ports < type->nr_ports)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
} while (!atomic_try_cmpxchg(&mdev_avail_ports,
|
} while (!atomic_try_cmpxchg(&mdev_avail_ports,
|
||||||
&avail_ports, avail_ports - nr_ports));
|
&avail_ports,
|
||||||
|
avail_ports - type->nr_ports));
|
||||||
|
|
||||||
mdev_state->nr_ports = nr_ports;
|
mdev_state->nr_ports = type->nr_ports;
|
||||||
mdev_state->irq_index = -1;
|
mdev_state->irq_index = -1;
|
||||||
mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE;
|
mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE;
|
||||||
mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE;
|
mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE;
|
||||||
@ -735,7 +751,7 @@ static int mtty_init_dev(struct vfio_device *vdev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_nr_ports:
|
err_nr_ports:
|
||||||
atomic_add(nr_ports, &mdev_avail_ports);
|
atomic_add(type->nr_ports, &mdev_avail_ports);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1242,11 +1258,9 @@ static const struct attribute_group *mdev_dev_groups[] = {
|
|||||||
static ssize_t name_show(struct mdev_type *mtype,
|
static ssize_t name_show(struct mdev_type *mtype,
|
||||||
struct mdev_type_attribute *attr, char *buf)
|
struct mdev_type_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
static const char *name_str[2] = { "Single port serial",
|
struct mtty_type *type = container_of(mtype, struct mtty_type, type);
|
||||||
"Dual port serial" };
|
|
||||||
|
|
||||||
return sysfs_emit(buf, "%s\n",
|
return sysfs_emit(buf, "%s\n", type->name);
|
||||||
name_str[mtype_get_type_group_id(mtype)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MDEV_TYPE_ATTR_RO(name);
|
static MDEV_TYPE_ATTR_RO(name);
|
||||||
@ -1255,9 +1269,10 @@ static ssize_t available_instances_show(struct mdev_type *mtype,
|
|||||||
struct mdev_type_attribute *attr,
|
struct mdev_type_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
unsigned int ports = mtype_get_type_group_id(mtype) + 1;
|
struct mtty_type *type = container_of(mtype, struct mtty_type, type);
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / ports);
|
return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) /
|
||||||
|
type->nr_ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MDEV_TYPE_ATTR_RO(available_instances);
|
static MDEV_TYPE_ATTR_RO(available_instances);
|
||||||
@ -1270,29 +1285,13 @@ static ssize_t device_api_show(struct mdev_type *mtype,
|
|||||||
|
|
||||||
static MDEV_TYPE_ATTR_RO(device_api);
|
static MDEV_TYPE_ATTR_RO(device_api);
|
||||||
|
|
||||||
static struct attribute *mdev_types_attrs[] = {
|
static const struct attribute *mdev_types_attrs[] = {
|
||||||
&mdev_type_attr_name.attr,
|
&mdev_type_attr_name.attr,
|
||||||
&mdev_type_attr_device_api.attr,
|
&mdev_type_attr_device_api.attr,
|
||||||
&mdev_type_attr_available_instances.attr,
|
&mdev_type_attr_available_instances.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group1 = {
|
|
||||||
.name = "1",
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group mdev_type_group2 = {
|
|
||||||
.name = "2",
|
|
||||||
.attrs = mdev_types_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute_group *mdev_type_groups[] = {
|
|
||||||
&mdev_type_group1,
|
|
||||||
&mdev_type_group2,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct vfio_device_ops mtty_dev_ops = {
|
static const struct vfio_device_ops mtty_dev_ops = {
|
||||||
.name = "vfio-mtty",
|
.name = "vfio-mtty",
|
||||||
.init = mtty_init_dev,
|
.init = mtty_init_dev,
|
||||||
@ -1311,7 +1310,7 @@ static struct mdev_driver mtty_driver = {
|
|||||||
},
|
},
|
||||||
.probe = mtty_probe,
|
.probe = mtty_probe,
|
||||||
.remove = mtty_remove,
|
.remove = mtty_remove,
|
||||||
.supported_type_groups = mdev_type_groups,
|
.types_attrs = mdev_types_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mtty_device_release(struct device *dev)
|
static void mtty_device_release(struct device *dev)
|
||||||
@ -1363,7 +1362,8 @@ static int __init mtty_dev_init(void)
|
|||||||
goto err_class;
|
goto err_class;
|
||||||
|
|
||||||
ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev,
|
ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev,
|
||||||
&mtty_driver);
|
&mtty_driver, mtty_mdev_types,
|
||||||
|
ARRAY_SIZE(mtty_mdev_types));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_device;
|
goto err_device;
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user