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.
Unified · Split
| @@ -103,7 +103,7 @@ structure to represent a mediated device's driver:: · 102 unmodified lines | |||
| 103 | struct mdev_driver { | 103 | struct mdev_driver { |
| 104 | int (*probe) (struct mdev_device *dev); | 104 | int (*probe) (struct mdev_device *dev); |
| 105 | void (*remove) (struct mdev_device *dev); | 105 | void (*remove) (struct mdev_device *dev); |
| 106 | struct attribute_group **supported_type_groups; | 106 | const struct attribute * const *types_attrs; |
| 107 | struct device_driver driver; | 107 | struct device_driver driver; |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| @@ -310,8 +310,8 @@ struct intel_vgpu_config { · 309 unmodified lines | |||
| 310 | const char *name; | 310 | const char *name; |
| 311 | }; | 311 | }; |
| 312 | 312 | ||
| 313 | #define NR_MAX_INTEL_VGPU_TYPES 20 | ||
| 314 | struct intel_vgpu_type { | 313 | struct intel_vgpu_type { |
| 314 | struct mdev_type type; | ||
| 315 | char name[16]; | 315 | char name[16]; |
| 316 | const struct intel_vgpu_config *conf; | 316 | const struct intel_vgpu_config *conf; |
| 317 | unsigned int avail_instance; | 317 | unsigned int avail_instance; |
| @@ -339,6 +339,7 @@ struct intel_gvt { · 21 unmodified lines | |||
| 339 | struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES]; | 339 | struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES]; |
| 340 | DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS); | 340 | DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS); |
| 341 | struct mdev_parent parent; | 341 | struct mdev_parent parent; |
| 342 | struct mdev_type **mdev_types; | ||
| 342 | struct intel_vgpu_type *types; | 343 | struct intel_vgpu_type *types; |
| 343 | unsigned int num_types; | 344 | unsigned int num_types; |
| 344 | struct intel_vgpu *idle_vgpu; | 345 | struct intel_vgpu *idle_vgpu; |
| @@ -117,17 +117,10 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 116 unmodified lines | |||
| 117 | struct mdev_type_attribute *attr, | 117 | struct mdev_type_attribute *attr, |
| 118 | char *buf) | 118 | char *buf) |
| 119 | { | 119 | { |
| 120 | struct intel_vgpu_type *type; | 120 | struct intel_vgpu_type *type = |
| 121 | unsigned int num = 0; | 121 | container_of(mtype, struct intel_vgpu_type, type); |
| 122 | struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt; | ||
| 123 | 122 | ||
| 124 | type = &gvt->types[mtype_get_type_group_id(mtype)]; | 123 | return sprintf(buf, "%u\n", type->avail_instance); |
| 125 | if (!type) | ||
| 126 | num = 0; | ||
| 127 | else | ||
| 128 | num = type->avail_instance; | ||
| 129 | |||
| 130 | return sprintf(buf, "%u\n", num); | ||
| 131 | } | 124 | } |
| 132 | 125 | ||
| 133 | static ssize_t device_api_show(struct mdev_type *mtype, | 126 | static ssize_t device_api_show(struct mdev_type *mtype, |
| @@ -139,12 +132,8 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 5 unmodified lines | |||
| 139 | static ssize_t description_show(struct mdev_type *mtype, | 132 | static ssize_t description_show(struct mdev_type *mtype, |
| 140 | struct mdev_type_attribute *attr, char *buf) | 133 | struct mdev_type_attribute *attr, char *buf) |
| 141 | { | 134 | { |
| 142 | struct intel_vgpu_type *type; | 135 | struct intel_vgpu_type *type = |
| 143 | struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt; | 136 | container_of(mtype, struct intel_vgpu_type, type); |
| 144 | |||
| 145 | type = &gvt->types[mtype_get_type_group_id(mtype)]; | ||
| 146 | if (!type) | ||
| 147 | return 0; | ||
| 148 | 137 | ||
| 149 | return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n" | 138 | return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n" |
| 150 | "fence: %d\nresolution: %s\n" | 139 | "fence: %d\nresolution: %s\n" |
| @@ -158,14 +147,7 @@ static ssize_t description_show(struct mdev_type *mtype, · 7 unmodified lines | |||
| 158 | static ssize_t name_show(struct mdev_type *mtype, | 147 | static ssize_t name_show(struct mdev_type *mtype, |
| 159 | struct mdev_type_attribute *attr, char *buf) | 148 | struct mdev_type_attribute *attr, char *buf) |
| 160 | { | 149 | { |
| 161 | struct intel_vgpu_type *type; | 150 | return sprintf(buf, "%s\n", mtype->sysfs_name); |
| 162 | struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt; | ||
| 163 | |||
| 164 | type = &gvt->types[mtype_get_type_group_id(mtype)]; | ||
| 165 | if (!type) | ||
| 166 | return 0; | ||
| 167 | |||
| 168 | return sprintf(buf, "%s\n", type->name); | ||
| 169 | } | 151 | } |
| 170 | 152 | ||
| 171 | static MDEV_TYPE_ATTR_RO(available_instances); | 153 | static MDEV_TYPE_ATTR_RO(available_instances); |
| @@ -173,7 +155,7 @@ static MDEV_TYPE_ATTR_RO(device_api); · 1 unmodified line | |||
| 173 | static MDEV_TYPE_ATTR_RO(description); | 155 | static MDEV_TYPE_ATTR_RO(description); |
| 174 | static MDEV_TYPE_ATTR_RO(name); | 156 | static MDEV_TYPE_ATTR_RO(name); |
| 175 | 157 | ||
| 176 | static struct attribute *gvt_type_attrs[] = { | 158 | static const struct attribute *gvt_type_attrs[] = { |
| 177 | &mdev_type_attr_available_instances.attr, | 159 | &mdev_type_attr_available_instances.attr, |
| 178 | &mdev_type_attr_device_api.attr, | 160 | &mdev_type_attr_device_api.attr, |
| 179 | &mdev_type_attr_description.attr, | 161 | &mdev_type_attr_description.attr, |
| @@ -181,51 +163,6 @@ static struct attribute *gvt_type_attrs[] = { · 1 unmodified line | |||
| 181 | NULL, | 163 | NULL, |
| 182 | }; | 164 | }; |
| 183 | 165 | ||
| 184 | static struct attribute_group *gvt_vgpu_type_groups[] = { | ||
| 185 | [0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL, | ||
| 186 | }; | ||
| 187 | |||
| 188 | static int intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt) | ||
| 189 | { | ||
| 190 | int i, j; | ||
| 191 | struct intel_vgpu_type *type; | ||
| 192 | struct attribute_group *group; | ||
| 193 | |||
| 194 | for (i = 0; i < gvt->num_types; i++) { | ||
| 195 | type = &gvt->types[i]; | ||
| 196 | |||
| 197 | group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); | ||
| 198 | if (!group) | ||
| 199 | goto unwind; | ||
| 200 | |||
| 201 | group->name = type->name; | ||
| 202 | group->attrs = gvt_type_attrs; | ||
| 203 | gvt_vgpu_type_groups[i] = group; | ||
| 204 | } | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | |||
| 208 | unwind: | ||
| 209 | for (j = 0; j < i; j++) { | ||
| 210 | group = gvt_vgpu_type_groups[j]; | ||
| 211 | kfree(group); | ||
| 212 | } | ||
| 213 | |||
| 214 | return -ENOMEM; | ||
| 215 | } | ||
| 216 | |||
| 217 | static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt) | ||
| 218 | { | ||
| 219 | int i; | ||
| 220 | struct attribute_group *group; | ||
| 221 | |||
| 222 | for (i = 0; i < gvt->num_types; i++) { | ||
| 223 | group = gvt_vgpu_type_groups[i]; | ||
| 224 | gvt_vgpu_type_groups[i] = NULL; | ||
| 225 | kfree(group); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, | 166 | static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, |
| 230 | unsigned long size) | 167 | unsigned long size) |
| 231 | { | 168 | { |
| @@ -1547,16 +1484,11 @@ static const struct attribute_group *intel_vgpu_groups[] = { · 1315 unmodified lines | |||
| 1547 | static int intel_vgpu_init_dev(struct vfio_device *vfio_dev) | 1484 | static int intel_vgpu_init_dev(struct vfio_device *vfio_dev) |
| 1548 | { | 1485 | { |
| 1549 | struct mdev_device *mdev = to_mdev_device(vfio_dev->dev); | 1486 | struct mdev_device *mdev = to_mdev_device(vfio_dev->dev); |
| 1550 | struct device *pdev = mdev_parent_dev(mdev); | ||
| 1551 | struct intel_gvt *gvt = kdev_to_i915(pdev)->gvt; | ||
| 1552 | struct intel_vgpu_type *type; | ||
| 1553 | struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev); | 1487 | struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev); |
| 1488 | struct intel_vgpu_type *type = | ||
| 1489 | container_of(mdev->type, struct intel_vgpu_type, type); | ||
| 1554 | 1490 | ||
| 1555 | type = &gvt->types[mdev_get_type_group_id(mdev)]; | 1491 | vgpu->gvt = kdev_to_i915(mdev_parent_dev(mdev))->gvt; |
| 1556 | if (!type) | ||
| 1557 | return -EINVAL; | ||
| 1558 | |||
| 1559 | vgpu->gvt = gvt; | ||
| 1560 | return intel_gvt_create_vgpu(vgpu, type->conf); | 1492 | return intel_gvt_create_vgpu(vgpu, type->conf); |
| 1561 | } | 1493 | } |
| 1562 | 1494 | ||
| @@ -1625,7 +1557,7 @@ static struct mdev_driver intel_vgpu_mdev_driver = { · 62 unmodified lines | |||
| 1625 | }, | 1557 | }, |
| 1626 | .probe = intel_vgpu_probe, | 1558 | .probe = intel_vgpu_probe, |
| 1627 | .remove = intel_vgpu_remove, | 1559 | .remove = intel_vgpu_remove, |
| 1628 | .supported_type_groups = gvt_vgpu_type_groups, | 1560 | .types_attrs = gvt_type_attrs, |
| 1629 | }; | 1561 | }; |
| 1630 | 1562 | ||
| 1631 | int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn) | 1563 | 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) · 292 unmodified lines | |||
| 1924 | return; | 1856 | return; |
| 1925 | 1857 | ||
| 1926 | mdev_unregister_parent(&gvt->parent); | 1858 | mdev_unregister_parent(&gvt->parent); |
| 1927 | intel_gvt_cleanup_vgpu_type_groups(gvt); | ||
| 1928 | intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu); | 1859 | intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu); |
| 1929 | intel_gvt_clean_vgpu_types(gvt); | 1860 | intel_gvt_clean_vgpu_types(gvt); |
| 1930 | 1861 | ||
| @@ -2024,20 +1955,15 @@ static int intel_gvt_init_device(struct drm_i915_private *i915) · 93 unmodified lines | |||
| 2024 | 1955 | ||
| 2025 | intel_gvt_debugfs_init(gvt); | 1956 | intel_gvt_debugfs_init(gvt); |
| 2026 | 1957 | ||
| 2027 | ret = intel_gvt_init_vgpu_type_groups(gvt); | ||
| 2028 | if (ret) | ||
| 2029 | goto out_destroy_idle_vgpu; | ||
| 2030 | |||
| 2031 | ret = mdev_register_parent(&gvt->parent, i915->drm.dev, | 1958 | ret = mdev_register_parent(&gvt->parent, i915->drm.dev, |
| 2032 | &intel_vgpu_mdev_driver); | 1959 | &intel_vgpu_mdev_driver, |
| 1960 | gvt->mdev_types, gvt->num_types); | ||
| 2033 | if (ret) | 1961 | if (ret) |
| 2034 | goto out_cleanup_vgpu_type_groups; | 1962 | goto out_destroy_idle_vgpu; |
| 2035 | 1963 | ||
| 2036 | gvt_dbg_core("gvt device initialization is done\n"); | 1964 | gvt_dbg_core("gvt device initialization is done\n"); |
| 2037 | return 0; | 1965 | return 0; |
| 2038 | 1966 | ||
| 2039 | out_cleanup_vgpu_type_groups: | ||
| 2040 | intel_gvt_cleanup_vgpu_type_groups(gvt); | ||
| 2041 | out_destroy_idle_vgpu: | 1967 | out_destroy_idle_vgpu: |
| 2042 | intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu); | 1968 | intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu); |
| 2043 | intel_gvt_debugfs_clean(gvt); | 1969 | intel_gvt_debugfs_clean(gvt); |
| @@ -113,13 +113,18 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) · 112 unmodified lines | |||
| 113 | if (!gvt->types) | 113 | if (!gvt->types) |
| 114 | return -ENOMEM; | 114 | return -ENOMEM; |
| 115 | 115 | ||
| 116 | gvt->mdev_types = kcalloc(num_types, sizeof(*gvt->mdev_types), | ||
| 117 | GFP_KERNEL); | ||
| 118 | if (!gvt->mdev_types) | ||
| 119 | goto out_free_types; | ||
| 120 | |||
| 116 | for (i = 0; i < num_types; ++i) { | 121 | for (i = 0; i < num_types; ++i) { |
| 117 | const struct intel_vgpu_config *conf = &intel_vgpu_configs[i]; | 122 | const struct intel_vgpu_config *conf = &intel_vgpu_configs[i]; |
| 118 | 123 | ||
| 119 | if (low_avail / conf->low_mm == 0) | 124 | if (low_avail / conf->low_mm == 0) |
| 120 | break; | 125 | break; |
| 121 | if (conf->weight < 1 || conf->weight > VGPU_MAX_WEIGHT) | 126 | if (conf->weight < 1 || conf->weight > VGPU_MAX_WEIGHT) |
| 122 | goto out_free_types; | 127 | goto out_free_mdev_types; |
| 123 | 128 | ||
| 124 | sprintf(gvt->types[i].name, "GVTg_V%u_%s", | 129 | sprintf(gvt->types[i].name, "GVTg_V%u_%s", |
| 125 | GRAPHICS_VER(gvt->gt->i915) == 8 ? 4 : 5, conf->name); | 130 | GRAPHICS_VER(gvt->gt->i915) == 8 ? 4 : 5, conf->name); |
| @@ -131,11 +136,16 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) · 5 unmodified lines | |||
| 131 | i, gvt->types[i].name, gvt->types[i].avail_instance, | 136 | i, gvt->types[i].name, gvt->types[i].avail_instance, |
| 132 | conf->low_mm, conf->high_mm, conf->fence, | 137 | conf->low_mm, conf->high_mm, conf->fence, |
| 133 | conf->weight, vgpu_edid_str(conf->edid)); | 138 | conf->weight, vgpu_edid_str(conf->edid)); |
| 139 | |||
| 140 | gvt->mdev_types[i] = &gvt->types[i].type; | ||
| 141 | gvt->mdev_types[i]->sysfs_name = gvt->types[i].name; | ||
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | gvt->num_types = i; | 144 | gvt->num_types = i; |
| 137 | return 0; | 145 | return 0; |
| 138 | 146 | ||
| 147 | out_free_mdev_types: | ||
| 148 | kfree(gvt->mdev_types); | ||
| 139 | out_free_types: | 149 | out_free_types: |
| 140 | kfree(gvt->types); | 150 | kfree(gvt->types); |
| 141 | return -EINVAL; | 151 | return -EINVAL; |
| @@ -143,6 +153,7 @@ out_free_types: · 1 unmodified line | |||
| 143 | 153 | ||
| 144 | void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt) | 154 | void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt) |
| 145 | { | 155 | { |
| 156 | kfree(gvt->mdev_types); | ||
| 146 | kfree(gvt->types); | 157 | kfree(gvt->types); |
| 147 | } | 158 | } |
| 148 | 159 | ||
| @@ -202,7 +202,6 @@ static void vfio_ccw_free_private(struct vfio_ccw_private *private) · 201 unmodified lines | |||
| 202 | mutex_destroy(&private->io_mutex); | 202 | mutex_destroy(&private->io_mutex); |
| 203 | kfree(private); | 203 | kfree(private); |
| 204 | } | 204 | } |
| 205 | |||
| 206 | static int vfio_ccw_sch_probe(struct subchannel *sch) | 205 | static int vfio_ccw_sch_probe(struct subchannel *sch) |
| 207 | { | 206 | { |
| 208 | struct pmcw *pmcw = &sch->schib.pmcw; | 207 | struct pmcw *pmcw = &sch->schib.pmcw; |
| @@ -221,8 +220,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) · 12 unmodified lines | |||
| 221 | 220 | ||
| 222 | dev_set_drvdata(&sch->dev, private); | 221 | dev_set_drvdata(&sch->dev, private); |
| 223 | 222 | ||
| 223 | private->mdev_type.sysfs_name = "io"; | ||
| 224 | private->mdev_types[0] = &private->mdev_type; | ||
| 224 | ret = mdev_register_parent(&private->parent, &sch->dev, | 225 | ret = mdev_register_parent(&private->parent, &sch->dev, |
| 225 | &vfio_ccw_mdev_driver); | 226 | &vfio_ccw_mdev_driver, |
| 227 | private->mdev_types, 1); | ||
| 226 | if (ret) | 228 | if (ret) |
| 227 | goto out_free; | 229 | goto out_free; |
| 228 | 230 | ||
| @@ -69,23 +69,13 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 68 unmodified lines | |||
| 69 | } | 69 | } |
| 70 | static MDEV_TYPE_ATTR_RO(available_instances); | 70 | static MDEV_TYPE_ATTR_RO(available_instances); |
| 71 | 71 | ||
| 72 | static struct attribute *mdev_types_attrs[] = { | 72 | static const struct attribute *mdev_types_attrs[] = { |
| 73 | &mdev_type_attr_name.attr, | 73 | &mdev_type_attr_name.attr, |
| 74 | &mdev_type_attr_device_api.attr, | 74 | &mdev_type_attr_device_api.attr, |
| 75 | &mdev_type_attr_available_instances.attr, | 75 | &mdev_type_attr_available_instances.attr, |
| 76 | NULL, | 76 | NULL, |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | static struct attribute_group mdev_type_group = { | ||
| 80 | .name = "io", | ||
| 81 | .attrs = mdev_types_attrs, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static struct attribute_group *mdev_type_groups[] = { | ||
| 85 | &mdev_type_group, | ||
| 86 | NULL, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev) | 79 | static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev) |
| 90 | { | 80 | { |
| 91 | struct vfio_ccw_private *private = | 81 | struct vfio_ccw_private *private = |
| @@ -646,5 +636,5 @@ struct mdev_driver vfio_ccw_mdev_driver = { · 554 unmodified lines | |||
| 646 | }, | 636 | }, |
| 647 | .probe = vfio_ccw_mdev_probe, | 637 | .probe = vfio_ccw_mdev_probe, |
| 648 | .remove = vfio_ccw_mdev_remove, | 638 | .remove = vfio_ccw_mdev_remove, |
| 649 | .supported_type_groups = mdev_type_groups, | 639 | .types_attrs = mdev_types_attrs, |
| 650 | }; | 640 | }; |
| @@ -120,6 +120,8 @@ struct vfio_ccw_private { · 119 unmodified lines | |||
| 120 | struct completion release_comp; | 120 | struct completion release_comp; |
| 121 | 121 | ||
| 122 | struct mdev_parent parent; | 122 | struct mdev_parent parent; |
| 123 | struct mdev_type mdev_type; | ||
| 124 | struct mdev_type *mdev_types[1]; | ||
| 123 | } __aligned(8); | 125 | } __aligned(8); |
| 124 | 126 | ||
| 125 | int vfio_ccw_sch_quiesce(struct subchannel *sch); | 127 | int vfio_ccw_sch_quiesce(struct subchannel *sch); |
| @@ -816,23 +816,13 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 815 unmodified lines | |||
| 816 | 816 | ||
| 817 | static MDEV_TYPE_ATTR_RO(device_api); | 817 | static MDEV_TYPE_ATTR_RO(device_api); |
| 818 | 818 | ||
| 819 | static struct attribute *vfio_ap_mdev_type_attrs[] = { | 819 | static const struct attribute *vfio_ap_mdev_type_attrs[] = { |
| 820 | &mdev_type_attr_name.attr, | 820 | &mdev_type_attr_name.attr, |
| 821 | &mdev_type_attr_device_api.attr, | 821 | &mdev_type_attr_device_api.attr, |
| 822 | &mdev_type_attr_available_instances.attr, | 822 | &mdev_type_attr_available_instances.attr, |
| 823 | NULL, | 823 | NULL, |
| 824 | }; | 824 | }; |
| 825 | 825 | ||
| 826 | static struct attribute_group vfio_ap_mdev_hwvirt_type_group = { | ||
| 827 | .name = VFIO_AP_MDEV_TYPE_HWVIRT, | ||
| 828 | .attrs = vfio_ap_mdev_type_attrs, | ||
| 829 | }; | ||
| 830 | |||
| 831 | static struct attribute_group *vfio_ap_mdev_type_groups[] = { | ||
| 832 | &vfio_ap_mdev_hwvirt_type_group, | ||
| 833 | NULL, | ||
| 834 | }; | ||
| 835 | |||
| 836 | #define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \ | 826 | #define MDEV_SHARING_ERR "Userspace may not re-assign queue %02lx.%04lx " \ |
| 837 | "already assigned to %s" | 827 | "already assigned to %s" |
| 838 | 828 | ||
| @@ -1817,7 +1807,7 @@ static struct mdev_driver vfio_ap_matrix_driver = { · 978 unmodified lines | |||
| 1817 | }, | 1807 | }, |
| 1818 | .probe = vfio_ap_mdev_probe, | 1808 | .probe = vfio_ap_mdev_probe, |
| 1819 | .remove = vfio_ap_mdev_remove, | 1809 | .remove = vfio_ap_mdev_remove, |
| 1820 | .supported_type_groups = vfio_ap_mdev_type_groups, | 1810 | .types_attrs = vfio_ap_mdev_type_attrs, |
| 1821 | }; | 1811 | }; |
| 1822 | 1812 | ||
| 1823 | int vfio_ap_mdev_register(void) | 1813 | int vfio_ap_mdev_register(void) |
| @@ -1830,8 +1820,11 @@ int vfio_ap_mdev_register(void) · 6 unmodified lines | |||
| 1830 | if (ret) | 1820 | if (ret) |
| 1831 | return ret; | 1821 | return ret; |
| 1832 | 1822 | ||
| 1823 | matrix_dev->mdev_type.sysfs_name = VFIO_AP_MDEV_TYPE_HWVIRT; | ||
| 1824 | matrix_dev->mdev_types[0] = &matrix_dev->mdev_type; | ||
| 1833 | ret = mdev_register_parent(&matrix_dev->parent, &matrix_dev->device, | 1825 | ret = mdev_register_parent(&matrix_dev->parent, &matrix_dev->device, |
| 1834 | &vfio_ap_matrix_driver); | 1826 | &vfio_ap_matrix_driver, |
| 1827 | matrix_dev->mdev_types, 1); | ||
| 1835 | if (ret) | 1828 | if (ret) |
| 1836 | goto err_driver; | 1829 | goto err_driver; |
| 1837 | return 0; | 1830 | return 0; |
| @@ -53,6 +53,8 @@ struct ap_matrix_dev { · 52 unmodified lines | |||
| 53 | struct ap_driver *vfio_ap_drv; | 53 | struct ap_driver *vfio_ap_drv; |
| 54 | struct mutex guests_lock; /* serializes access to each KVM guest */ | 54 | struct mutex guests_lock; /* serializes access to each KVM guest */ |
| 55 | struct mdev_parent parent; | 55 | struct mdev_parent parent; |
| 56 | struct mdev_type mdev_type; | ||
| 57 | struct mdev_type *mdev_types[]; | ||
| 56 | }; | 58 | }; |
| 57 | 59 | ||
| 58 | extern struct ap_matrix_dev *matrix_dev; | 60 | extern struct ap_matrix_dev *matrix_dev; |
| @@ -29,26 +29,6 @@ struct device *mdev_parent_dev(struct mdev_device *mdev) · 28 unmodified lines | |||
| 29 | } | 29 | } |
| 30 | EXPORT_SYMBOL(mdev_parent_dev); | 30 | EXPORT_SYMBOL(mdev_parent_dev); |
| 31 | 31 | ||
| 32 | /* | ||
| 33 | * Return the index in supported_type_groups that this mdev_device was created | ||
| 34 | * from. | ||
| 35 | */ | ||
| 36 | unsigned int mdev_get_type_group_id(struct mdev_device *mdev) | ||
| 37 | { | ||
| 38 | return mdev->type->type_group_id; | ||
| 39 | } | ||
| 40 | EXPORT_SYMBOL(mdev_get_type_group_id); | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Used in mdev_type_attribute sysfs functions to return the index in the | ||
| 44 | * supported_type_groups that the sysfs is called from. | ||
| 45 | */ | ||
| 46 | unsigned int mtype_get_type_group_id(struct mdev_type *mtype) | ||
| 47 | { | ||
| 48 | return mtype->type_group_id; | ||
| 49 | } | ||
| 50 | EXPORT_SYMBOL(mtype_get_type_group_id); | ||
| 51 | |||
| 52 | /* | 32 | /* |
| 53 | * Used in mdev_type_attribute sysfs functions to return the parent struct | 33 | * Used in mdev_type_attribute sysfs functions to return the parent struct |
| 54 | * device | 34 | * device |
| @@ -85,6 +65,8 @@ static int mdev_device_remove_cb(struct device *dev, void *data) · 30 unmodified lines | |||
| 85 | * @parent: parent structure registered | 65 | * @parent: parent structure registered |
| 86 | * @dev: device structure representing parent device. | 66 | * @dev: device structure representing parent device. |
| 87 | * @mdev_driver: Device driver to bind to the newly created mdev | 67 | * @mdev_driver: Device driver to bind to the newly created mdev |
| 68 | * @types: Array of supported mdev types | ||
| 69 | * @nr_types: Number of entries in @types | ||
| 88 | * | 70 | * |
| 89 | * Registers the @parent stucture as a parent for mdev types and thus mdev | 71 | * Registers the @parent stucture as a parent for mdev types and thus mdev |
| 90 | * devices. The caller needs to hold a reference on @dev that must not be | 72 | * 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) · 2 unmodified lines | |||
| 93 | * Returns a negative value on error, otherwise 0. | 75 | * Returns a negative value on error, otherwise 0. |
| 94 | */ | 76 | */ |
| 95 | int mdev_register_parent(struct mdev_parent *parent, struct device *dev, | 77 | int mdev_register_parent(struct mdev_parent *parent, struct device *dev, |
| 96 | struct mdev_driver *mdev_driver) | 78 | struct mdev_driver *mdev_driver, struct mdev_type **types, |
| 79 | unsigned int nr_types) | ||
| 97 | { | 80 | { |
| 98 | char *env_string = "MDEV_STATE=registered"; | 81 | char *env_string = "MDEV_STATE=registered"; |
| 99 | char *envp[] = { env_string, NULL }; | 82 | char *envp[] = { env_string, NULL }; |
| 100 | int ret; | 83 | int ret; |
| 101 | 84 | ||
| 102 | /* check for mandatory ops */ | ||
| 103 | if (!mdev_driver->supported_type_groups) | ||
| 104 | return -EINVAL; | ||
| 105 | |||
| 106 | memset(parent, 0, sizeof(*parent)); | 85 | memset(parent, 0, sizeof(*parent)); |
| 107 | init_rwsem(&parent->unreg_sem); | 86 | init_rwsem(&parent->unreg_sem); |
| 108 | parent->dev = dev; | 87 | parent->dev = dev; |
| 109 | parent->mdev_driver = mdev_driver; | 88 | parent->mdev_driver = mdev_driver; |
| 89 | parent->types = types; | ||
| 90 | parent->nr_types = nr_types; | ||
| 110 | 91 | ||
| 111 | if (!mdev_bus_compat_class) { | 92 | if (!mdev_bus_compat_class) { |
| 112 | mdev_bus_compat_class = class_compat_register("mdev_bus"); | 93 | mdev_bus_compat_class = class_compat_register("mdev_bus"); |
| @@ -56,10 +56,9 @@ EXPORT_SYMBOL_GPL(mdev_bus_type); · 55 unmodified lines | |||
| 56 | **/ | 56 | **/ |
| 57 | int mdev_register_driver(struct mdev_driver *drv) | 57 | int mdev_register_driver(struct mdev_driver *drv) |
| 58 | { | 58 | { |
| 59 | /* initialize common driver fields */ | 59 | if (!drv->types_attrs) |
| 60 | return -EINVAL; | ||
| 60 | drv->driver.bus = &mdev_bus_type; | 61 | drv->driver.bus = &mdev_bus_type; |
| 61 | |||
| 62 | /* register with core */ | ||
| 63 | return driver_register(&drv->driver); | 62 | return driver_register(&drv->driver); |
| 64 | } | 63 | } |
| 65 | EXPORT_SYMBOL(mdev_register_driver); | 64 | EXPORT_SYMBOL(mdev_register_driver); |
| @@ -13,14 +13,6 @@ · 12 unmodified lines | |||
| 13 | int mdev_bus_register(void); | 13 | int mdev_bus_register(void); |
| 14 | void mdev_bus_unregister(void); | 14 | void mdev_bus_unregister(void); |
| 15 | 15 | ||
| 16 | struct mdev_type { | ||
| 17 | struct kobject kobj; | ||
| 18 | struct kobject *devices_kobj; | ||
| 19 | struct mdev_parent *parent; | ||
| 20 | struct list_head next; | ||
| 21 | unsigned int type_group_id; | ||
| 22 | }; | ||
| 23 | |||
| 24 | extern const struct attribute_group *mdev_device_groups[]; | 16 | extern const struct attribute_group *mdev_device_groups[]; |
| 25 | 17 | ||
| 26 | #define to_mdev_type_attr(_attr) \ | 18 | #define to_mdev_type_attr(_attr) \ |
| @@ -82,7 +82,6 @@ static void mdev_type_release(struct kobject *kobj) · 81 unmodified lines | |||
| 82 | pr_debug("Releasing group %s\n", kobj->name); | 82 | pr_debug("Releasing group %s\n", kobj->name); |
| 83 | /* Pairs with the get in add_mdev_supported_type() */ | 83 | /* Pairs with the get in add_mdev_supported_type() */ |
| 84 | put_device(type->parent->dev); | 84 | put_device(type->parent->dev); |
| 85 | kfree(type); | ||
| 86 | } | 85 | } |
| 87 | 86 | ||
| 88 | static struct kobj_type mdev_type_ktype = { | 87 | static struct kobj_type mdev_type_ktype = { |
| @@ -90,35 +89,21 @@ static struct kobj_type mdev_type_ktype = { · 1 unmodified line | |||
| 90 | .release = mdev_type_release, | 89 | .release = mdev_type_release, |
| 91 | }; | 90 | }; |
| 92 | 91 | ||
| 93 | static struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent, | 92 | static int mdev_type_add(struct mdev_parent *parent, struct mdev_type *type) |
| 94 | unsigned int type_group_id) | ||
| 95 | { | 93 | { |
| 96 | struct mdev_type *type; | ||
| 97 | struct attribute_group *group = | ||
| 98 | parent->mdev_driver->supported_type_groups[type_group_id]; | ||
| 99 | int ret; | 94 | int ret; |
| 100 | 95 | ||
| 101 | if (!group->name) { | ||
| 102 | pr_err("%s: Type name empty!\n", __func__); | ||
| 103 | return ERR_PTR(-EINVAL); | ||
| 104 | } | ||
| 105 | |||
| 106 | type = kzalloc(sizeof(*type), GFP_KERNEL); | ||
| 107 | if (!type) | ||
| 108 | return ERR_PTR(-ENOMEM); | ||
| 109 | |||
| 110 | type->kobj.kset = parent->mdev_types_kset; | 96 | type->kobj.kset = parent->mdev_types_kset; |
| 111 | type->parent = parent; | 97 | type->parent = parent; |
| 112 | /* Pairs with the put in mdev_type_release() */ | 98 | /* Pairs with the put in mdev_type_release() */ |
| 113 | get_device(parent->dev); | 99 | get_device(parent->dev); |
| 114 | type->type_group_id = type_group_id; | ||
| 115 | 100 | ||
| 116 | ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL, | 101 | ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL, |
| 117 | "%s-%s", dev_driver_string(parent->dev), | 102 | "%s-%s", dev_driver_string(parent->dev), |
| 118 | group->name); | 103 | type->sysfs_name); |
| 119 | if (ret) { | 104 | if (ret) { |
| 120 | kobject_put(&type->kobj); | 105 | kobject_put(&type->kobj); |
| 121 | return ERR_PTR(ret); | 106 | return ret; |
| 122 | } | 107 | } |
| 123 | 108 | ||
| 124 | ret = sysfs_create_file(&type->kobj, &mdev_type_attr_create.attr); | 109 | 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, · 6 unmodified lines | |||
| 131 | goto attr_devices_failed; | 116 | goto attr_devices_failed; |
| 132 | } | 117 | } |
| 133 | 118 | ||
| 134 | ret = sysfs_create_files(&type->kobj, | 119 | ret = sysfs_create_files(&type->kobj, parent->mdev_driver->types_attrs); |
| 135 | (const struct attribute **)group->attrs); | 120 | if (ret) |
| 136 | if (ret) { | ||
| 137 | ret = -ENOMEM; | ||
| 138 | goto attrs_failed; | 121 | goto attrs_failed; |
| 139 | } | 122 | return 0; |
| 140 | return type; | ||
| 141 | 123 | ||
| 142 | attrs_failed: | 124 | attrs_failed: |
| 143 | kobject_put(type->devices_kobj); | 125 | kobject_put(type->devices_kobj); |
| @@ -146,78 +128,49 @@ attr_devices_failed: · 2 unmodified lines | |||
| 146 | attr_create_failed: | 128 | attr_create_failed: |
| 147 | kobject_del(&type->kobj); | 129 | kobject_del(&type->kobj); |
| 148 | kobject_put(&type->kobj); | 130 | kobject_put(&type->kobj); |
| 149 | return ERR_PTR(ret); | 131 | return ret; |
| 150 | } | 132 | } |
| 151 | 133 | ||
| 152 | static void remove_mdev_supported_type(struct mdev_type *type) | 134 | static void mdev_type_remove(struct mdev_type *type) |
| 153 | { | 135 | { |
| 154 | struct attribute_group *group = | 136 | sysfs_remove_files(&type->kobj, type->parent->mdev_driver->types_attrs); |
| 155 | type->parent->mdev_driver->supported_type_groups[type->type_group_id]; | ||
| 156 | 137 | ||
| 157 | sysfs_remove_files(&type->kobj, | ||
| 158 | (const struct attribute **)group->attrs); | ||
| 159 | kobject_put(type->devices_kobj); | 138 | kobject_put(type->devices_kobj); |
| 160 | sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr); | 139 | sysfs_remove_file(&type->kobj, &mdev_type_attr_create.attr); |
| 161 | kobject_del(&type->kobj); | 140 | kobject_del(&type->kobj); |
| 162 | kobject_put(&type->kobj); | 141 | kobject_put(&type->kobj); |
| 163 | } | 142 | } |
| 164 | 143 | ||
| 165 | static int add_mdev_supported_type_groups(struct mdev_parent *parent) | ||
| 166 | { | ||
| 167 | int i; | ||
| 168 | |||
| 169 | for (i = 0; parent->mdev_driver->supported_type_groups[i]; i++) { | ||
| 170 | struct mdev_type *type; | ||
| 171 | |||
| 172 | type = add_mdev_supported_type(parent, i); | ||
| 173 | if (IS_ERR(type)) { | ||
| 174 | struct mdev_type *ltype, *tmp; | ||
| 175 | |||
| 176 | list_for_each_entry_safe(ltype, tmp, &parent->type_list, | ||
| 177 | next) { | ||
| 178 | list_del(<ype->next); | ||
| 179 | remove_mdev_supported_type(ltype); | ||
| 180 | } | ||
| 181 | return PTR_ERR(type); | ||
| 182 | } | ||
| 183 | list_add(&type->next, &parent->type_list); | ||
| 184 | } | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* mdev sysfs functions */ | 144 | /* mdev sysfs functions */ |
| 189 | void parent_remove_sysfs_files(struct mdev_parent *parent) | 145 | void parent_remove_sysfs_files(struct mdev_parent *parent) |
| 190 | { | 146 | { |
| 191 | struct mdev_type *type, *tmp; | 147 | int i; |
| 192 | |||
| 193 | list_for_each_entry_safe(type, tmp, &parent->type_list, next) { | ||
| 194 | list_del(&type->next); | ||
| 195 | remove_mdev_supported_type(type); | ||
| 196 | } | ||
| 197 | 148 | ||
| 149 | for (i = 0; i < parent->nr_types; i++) | ||
| 150 | mdev_type_remove(parent->types[i]); | ||
| 198 | kset_unregister(parent->mdev_types_kset); | 151 | kset_unregister(parent->mdev_types_kset); |
| 199 | } | 152 | } |
| 200 | 153 | ||
| 201 | int parent_create_sysfs_files(struct mdev_parent *parent) | 154 | int parent_create_sysfs_files(struct mdev_parent *parent) |
| 202 | { | 155 | { |
| 203 | int ret; | 156 | int ret, i; |
| 204 | 157 | ||
| 205 | parent->mdev_types_kset = kset_create_and_add("mdev_supported_types", | 158 | parent->mdev_types_kset = kset_create_and_add("mdev_supported_types", |
| 206 | NULL, &parent->dev->kobj); | 159 | NULL, &parent->dev->kobj); |
| 207 | |||
| 208 | if (!parent->mdev_types_kset) | 160 | if (!parent->mdev_types_kset) |
| 209 | return -ENOMEM; | 161 | return -ENOMEM; |
| 210 | 162 | ||
| 211 | INIT_LIST_HEAD(&parent->type_list); | 163 | for (i = 0; i < parent->nr_types; i++) { |
| 212 | 164 | ret = mdev_type_add(parent, parent->types[i]); | |
| 213 | ret = add_mdev_supported_type_groups(parent); | 165 | if (ret) |
| 214 | if (ret) | 166 | goto out_err; |
| 215 | goto create_err; | 167 | } |
| 216 | return 0; | 168 | return 0; |
| 217 | 169 | ||
| 218 | create_err: | 170 | out_err: |
| 219 | kset_unregister(parent->mdev_types_kset); | 171 | while (--i >= 0) |
| 220 | return ret; | 172 | mdev_type_remove(parent->types[i]); |
| 173 | return 0; | ||
| 221 | } | 174 | } |
| 222 | 175 | ||
| 223 | static ssize_t remove_store(struct device *dev, struct device_attribute *attr, | 176 | static ssize_t remove_store(struct device *dev, struct device_attribute *attr, |
| @@ -23,14 +23,27 @@ struct mdev_device { · 22 unmodified lines | |||
| 23 | bool active; | 23 | bool active; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | struct mdev_type { | ||
| 27 | /* set by the driver before calling mdev_register parent: */ | ||
| 28 | const char *sysfs_name; | ||
| 29 | |||
| 30 | /* set by the core, can be used drivers */ | ||
| 31 | struct mdev_parent *parent; | ||
| 32 | |||
| 33 | /* internal only */ | ||
| 34 | struct kobject kobj; | ||
| 35 | struct kobject *devices_kobj; | ||
| 36 | }; | ||
| 37 | |||
| 26 | /* embedded into the struct device that the mdev devices hang off */ | 38 | /* embedded into the struct device that the mdev devices hang off */ |
| 27 | struct mdev_parent { | 39 | struct mdev_parent { |
| 28 | struct device *dev; | 40 | struct device *dev; |
| 29 | struct mdev_driver *mdev_driver; | 41 | struct mdev_driver *mdev_driver; |
| 30 | struct kset *mdev_types_kset; | 42 | struct kset *mdev_types_kset; |
| 31 | struct list_head type_list; | ||
| 32 | /* Synchronize device creation/removal with parent unregistration */ | 43 | /* Synchronize device creation/removal with parent unregistration */ |
| 33 | struct rw_semaphore unreg_sem; | 44 | struct rw_semaphore unreg_sem; |
| 45 | struct mdev_type **types; | ||
| 46 | unsigned int nr_types; | ||
| 34 | }; | 47 | }; |
| 35 | 48 | ||
| 36 | static inline struct mdev_device *to_mdev_device(struct device *dev) | 49 | 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) · 1 unmodified line | |||
| 38 | return container_of(dev, struct mdev_device, dev); | 51 | return container_of(dev, struct mdev_device, dev); |
| 39 | } | 52 | } |
| 40 | 53 | ||
| 41 | unsigned int mdev_get_type_group_id(struct mdev_device *mdev); | ||
| 42 | unsigned int mtype_get_type_group_id(struct mdev_type *mtype); | ||
| 43 | struct device *mtype_get_parent_dev(struct mdev_type *mtype); | 54 | struct device *mtype_get_parent_dev(struct mdev_type *mtype); |
| 44 | 55 | ||
| 45 | /* interface for exporting mdev supported type attributes */ | 56 | /* interface for exporting mdev supported type attributes */ |
| @@ -66,22 +77,21 @@ struct mdev_type_attribute mdev_type_attr_##_name = \ · 20 unmodified lines | |||
| 66 | * struct mdev_driver - Mediated device driver | 77 | * struct mdev_driver - Mediated device driver |
| 67 | * @probe: called when new device created | 78 | * @probe: called when new device created |
| 68 | * @remove: called when device removed | 79 | * @remove: called when device removed |
| 69 | * @supported_type_groups: Attributes to define supported types. It is mandatory | 80 | * @types_attrs: attributes to the type kobjects. |
| 70 | * to provide supported types. | ||
| 71 | * @driver: device driver structure | 81 | * @driver: device driver structure |
| 72 | * | ||
| 73 | **/ | 82 | **/ |
| 74 | struct mdev_driver { | 83 | struct mdev_driver { |
| 75 | int (*probe)(struct mdev_device *dev); | 84 | int (*probe)(struct mdev_device *dev); |
| 76 | void (*remove)(struct mdev_device *dev); | 85 | void (*remove)(struct mdev_device *dev); |
| 77 | struct attribute_group **supported_type_groups; | 86 | const struct attribute * const *types_attrs; |
| 78 | struct device_driver driver; | 87 | struct device_driver driver; |
| 79 | }; | 88 | }; |
| 80 | 89 | ||
| 81 | extern struct bus_type mdev_bus_type; | 90 | extern struct bus_type mdev_bus_type; |
| 82 | 91 | ||
| 83 | int mdev_register_parent(struct mdev_parent *parent, struct device *dev, | 92 | int mdev_register_parent(struct mdev_parent *parent, struct device *dev, |
| 84 | struct mdev_driver *mdev_driver); | 93 | struct mdev_driver *mdev_driver, struct mdev_type **types, |
| 94 | unsigned int nr_types); | ||
| 85 | void mdev_unregister_parent(struct mdev_parent *parent); | 95 | void mdev_unregister_parent(struct mdev_parent *parent); |
| 86 | 96 | ||
| 87 | int mdev_register_driver(struct mdev_driver *drv); | 97 | int mdev_register_driver(struct mdev_driver *drv); |
| @@ -99,23 +99,27 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices"); · 98 unmodified lines | |||
| 99 | #define MBOCHS_TYPE_2 "medium" | 99 | #define MBOCHS_TYPE_2 "medium" |
| 100 | #define MBOCHS_TYPE_3 "large" | 100 | #define MBOCHS_TYPE_3 "large" |
| 101 | 101 | ||
| 102 | static const struct mbochs_type { | 102 | static struct mbochs_type { |
| 103 | struct mdev_type type; | ||
| 103 | const char *name; | 104 | const char *name; |
| 104 | u32 mbytes; | 105 | u32 mbytes; |
| 105 | u32 max_x; | 106 | u32 max_x; |
| 106 | u32 max_y; | 107 | u32 max_y; |
| 107 | } mbochs_types[] = { | 108 | } mbochs_types[] = { |
| 108 | { | 109 | { |
| 110 | .type.sysfs_name = MBOCHS_TYPE_1, | ||
| 109 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, | 111 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, |
| 110 | .mbytes = 4, | 112 | .mbytes = 4, |
| 111 | .max_x = 800, | 113 | .max_x = 800, |
| 112 | .max_y = 600, | 114 | .max_y = 600, |
| 113 | }, { | 115 | }, { |
| 116 | .type.sysfs_name = MBOCHS_TYPE_2, | ||
| 114 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, | 117 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, |
| 115 | .mbytes = 16, | 118 | .mbytes = 16, |
| 116 | .max_x = 1920, | 119 | .max_x = 1920, |
| 117 | .max_y = 1440, | 120 | .max_y = 1440, |
| 118 | }, { | 121 | }, { |
| 122 | .type.sysfs_name = MBOCHS_TYPE_3, | ||
| 119 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, | 123 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, |
| 120 | .mbytes = 64, | 124 | .mbytes = 64, |
| 121 | .max_x = 0, | 125 | .max_x = 0, |
| @@ -123,6 +127,11 @@ static const struct mbochs_type { · 1 unmodified line | |||
| 123 | }, | 127 | }, |
| 124 | }; | 128 | }; |
| 125 | 129 | ||
| 130 | static struct mdev_type *mbochs_mdev_types[] = { | ||
| 131 | &mbochs_types[0].type, | ||
| 132 | &mbochs_types[1].type, | ||
| 133 | &mbochs_types[2].type, | ||
| 134 | }; | ||
| 126 | 135 | ||
| 127 | static dev_t mbochs_devt; | 136 | static dev_t mbochs_devt; |
| 128 | static struct class *mbochs_class; | 137 | static struct class *mbochs_class; |
| @@ -510,8 +519,8 @@ static int mbochs_init_dev(struct vfio_device *vdev) · 381 unmodified lines | |||
| 510 | struct mdev_state *mdev_state = | 519 | struct mdev_state *mdev_state = |
| 511 | container_of(vdev, struct mdev_state, vdev); | 520 | container_of(vdev, struct mdev_state, vdev); |
| 512 | struct mdev_device *mdev = to_mdev_device(vdev->dev); | 521 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 513 | const struct mbochs_type *type = | 522 | struct mbochs_type *type = |
| 514 | &mbochs_types[mdev_get_type_group_id(mdev)]; | 523 | container_of(mdev->type, struct mbochs_type, type); |
| 515 | int avail_mbytes = atomic_read(&mbochs_avail_mbytes); | 524 | int avail_mbytes = atomic_read(&mbochs_avail_mbytes); |
| 516 | int ret = -ENOMEM; | 525 | int ret = -ENOMEM; |
| 517 | 526 | ||
| @@ -1345,8 +1354,8 @@ static const struct attribute_group *mdev_dev_groups[] = { · 827 unmodified lines | |||
| 1345 | static ssize_t name_show(struct mdev_type *mtype, | 1354 | static ssize_t name_show(struct mdev_type *mtype, |
| 1346 | struct mdev_type_attribute *attr, char *buf) | 1355 | struct mdev_type_attribute *attr, char *buf) |
| 1347 | { | 1356 | { |
| 1348 | const struct mbochs_type *type = | 1357 | struct mbochs_type *type = |
| 1349 | &mbochs_types[mtype_get_type_group_id(mtype)]; | 1358 | container_of(mtype, struct mbochs_type, type); |
| 1350 | 1359 | ||
| 1351 | return sprintf(buf, "%s\n", type->name); | 1360 | return sprintf(buf, "%s\n", type->name); |
| 1352 | } | 1361 | } |
| @@ -1355,8 +1364,8 @@ static MDEV_TYPE_ATTR_RO(name); · 2 unmodified lines | |||
| 1355 | static ssize_t description_show(struct mdev_type *mtype, | 1364 | static ssize_t description_show(struct mdev_type *mtype, |
| 1356 | struct mdev_type_attribute *attr, char *buf) | 1365 | struct mdev_type_attribute *attr, char *buf) |
| 1357 | { | 1366 | { |
| 1358 | const struct mbochs_type *type = | 1367 | struct mbochs_type *type = |
| 1359 | &mbochs_types[mtype_get_type_group_id(mtype)]; | 1368 | container_of(mtype, struct mbochs_type, type); |
| 1360 | 1369 | ||
| 1361 | return sprintf(buf, "virtual display, %d MB video memory\n", | 1370 | return sprintf(buf, "virtual display, %d MB video memory\n", |
| 1362 | type ? type->mbytes : 0); | 1371 | type ? type->mbytes : 0); |
| @@ -1367,8 +1376,8 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 4 unmodified lines | |||
| 1367 | struct mdev_type_attribute *attr, | 1376 | struct mdev_type_attribute *attr, |
| 1368 | char *buf) | 1377 | char *buf) |
| 1369 | { | 1378 | { |
| 1370 | const struct mbochs_type *type = | 1379 | struct mbochs_type *type = |
| 1371 | &mbochs_types[mtype_get_type_group_id(mtype)]; | 1380 | container_of(mtype, struct mbochs_type, type); |
| 1372 | int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes; | 1381 | int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes; |
| 1373 | 1382 | ||
| 1374 | return sprintf(buf, "%d\n", count); | 1383 | return sprintf(buf, "%d\n", count); |
| @@ -1382,7 +1391,7 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 7 unmodified lines | |||
| 1382 | } | 1391 | } |
| 1383 | static MDEV_TYPE_ATTR_RO(device_api); | 1392 | static MDEV_TYPE_ATTR_RO(device_api); |
| 1384 | 1393 | ||
| 1385 | static struct attribute *mdev_types_attrs[] = { | 1394 | static const struct attribute *mdev_types_attrs[] = { |
| 1386 | &mdev_type_attr_name.attr, | 1395 | &mdev_type_attr_name.attr, |
| 1387 | &mdev_type_attr_description.attr, | 1396 | &mdev_type_attr_description.attr, |
| 1388 | &mdev_type_attr_device_api.attr, | 1397 | &mdev_type_attr_device_api.attr, |
| @@ -1390,28 +1399,6 @@ static struct attribute *mdev_types_attrs[] = { · 1 unmodified line | |||
| 1390 | NULL, | 1399 | NULL, |
| 1391 | }; | 1400 | }; |
| 1392 | 1401 | ||
| 1393 | static struct attribute_group mdev_type_group1 = { | ||
| 1394 | .name = MBOCHS_TYPE_1, | ||
| 1395 | .attrs = mdev_types_attrs, | ||
| 1396 | }; | ||
| 1397 | |||
| 1398 | static struct attribute_group mdev_type_group2 = { | ||
| 1399 | .name = MBOCHS_TYPE_2, | ||
| 1400 | .attrs = mdev_types_attrs, | ||
| 1401 | }; | ||
| 1402 | |||
| 1403 | static struct attribute_group mdev_type_group3 = { | ||
| 1404 | .name = MBOCHS_TYPE_3, | ||
| 1405 | .attrs = mdev_types_attrs, | ||
| 1406 | }; | ||
| 1407 | |||
| 1408 | static struct attribute_group *mdev_type_groups[] = { | ||
| 1409 | &mdev_type_group1, | ||
| 1410 | &mdev_type_group2, | ||
| 1411 | &mdev_type_group3, | ||
| 1412 | NULL, | ||
| 1413 | }; | ||
| 1414 | |||
| 1415 | static const struct vfio_device_ops mbochs_dev_ops = { | 1402 | static const struct vfio_device_ops mbochs_dev_ops = { |
| 1416 | .close_device = mbochs_close_device, | 1403 | .close_device = mbochs_close_device, |
| 1417 | .init = mbochs_init_dev, | 1404 | .init = mbochs_init_dev, |
| @@ -1431,7 +1418,7 @@ static struct mdev_driver mbochs_driver = { · 13 unmodified lines | |||
| 1431 | }, | 1418 | }, |
| 1432 | .probe = mbochs_probe, | 1419 | .probe = mbochs_probe, |
| 1433 | .remove = mbochs_remove, | 1420 | .remove = mbochs_remove, |
| 1434 | .supported_type_groups = mdev_type_groups, | 1421 | .types_attrs = mdev_types_attrs, |
| 1435 | }; | 1422 | }; |
| 1436 | 1423 | ||
| 1437 | static const struct file_operations vd_fops = { | 1424 | static const struct file_operations vd_fops = { |
| @@ -1476,7 +1463,9 @@ static int __init mbochs_dev_init(void) · 38 unmodified lines | |||
| 1476 | if (ret) | 1463 | if (ret) |
| 1477 | goto err_class; | 1464 | goto err_class; |
| 1478 | 1465 | ||
| 1479 | ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver); | 1466 | ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver, |
| 1467 | mbochs_mdev_types, | ||
| 1468 | ARRAY_SIZE(mbochs_mdev_types)); | ||
| 1480 | if (ret) | 1469 | if (ret) |
| 1481 | goto err_device; | 1470 | goto err_device; |
| 1482 | 1471 | ||
| @@ -51,7 +51,8 @@ MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices"); · 50 unmodified lines | |||
| 51 | #define MDPY_TYPE_2 "xga" | 51 | #define MDPY_TYPE_2 "xga" |
| 52 | #define MDPY_TYPE_3 "hd" | 52 | #define MDPY_TYPE_3 "hd" |
| 53 | 53 | ||
| 54 | static const struct mdpy_type { | 54 | static struct mdpy_type { |
| 55 | struct mdev_type type; | ||
| 55 | const char *name; | 56 | const char *name; |
| 56 | u32 format; | 57 | u32 format; |
| 57 | u32 bytepp; | 58 | u32 bytepp; |
| @@ -59,18 +60,21 @@ static const struct mdpy_type { · 1 unmodified line | |||
| 59 | u32 height; | 60 | u32 height; |
| 60 | } mdpy_types[] = { | 61 | } mdpy_types[] = { |
| 61 | { | 62 | { |
| 63 | .type.sysfs_name = MDPY_TYPE_1, | ||
| 62 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_1, | 64 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_1, |
| 63 | .format = DRM_FORMAT_XRGB8888, | 65 | .format = DRM_FORMAT_XRGB8888, |
| 64 | .bytepp = 4, | 66 | .bytepp = 4, |
| 65 | .width = 640, | 67 | .width = 640, |
| 66 | .height = 480, | 68 | .height = 480, |
| 67 | }, { | 69 | }, { |
| 70 | .type.sysfs_name = MDPY_TYPE_2, | ||
| 68 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_2, | 71 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_2, |
| 69 | .format = DRM_FORMAT_XRGB8888, | 72 | .format = DRM_FORMAT_XRGB8888, |
| 70 | .bytepp = 4, | 73 | .bytepp = 4, |
| 71 | .width = 1024, | 74 | .width = 1024, |
| 72 | .height = 768, | 75 | .height = 768, |
| 73 | }, { | 76 | }, { |
| 77 | .type.sysfs_name = MDPY_TYPE_3, | ||
| 74 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_3, | 78 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_3, |
| 75 | .format = DRM_FORMAT_XRGB8888, | 79 | .format = DRM_FORMAT_XRGB8888, |
| 76 | .bytepp = 4, | 80 | .bytepp = 4, |
| @@ -79,6 +83,12 @@ static const struct mdpy_type { · 2 unmodified lines | |||
| 79 | }, | 83 | }, |
| 80 | }; | 84 | }; |
| 81 | 85 | ||
| 86 | static struct mdev_type *mdpy_mdev_types[] = { | ||
| 87 | &mdpy_types[0].type, | ||
| 88 | &mdpy_types[1].type, | ||
| 89 | &mdpy_types[2].type, | ||
| 90 | }; | ||
| 91 | |||
| 82 | static dev_t mdpy_devt; | 92 | static dev_t mdpy_devt; |
| 83 | static struct class *mdpy_class; | 93 | static struct class *mdpy_class; |
| 84 | static struct cdev mdpy_cdev; | 94 | static struct cdev mdpy_cdev; |
| @@ -222,7 +232,7 @@ static int mdpy_init_dev(struct vfio_device *vdev) · 137 unmodified lines | |||
| 222 | container_of(vdev, struct mdev_state, vdev); | 232 | container_of(vdev, struct mdev_state, vdev); |
| 223 | struct mdev_device *mdev = to_mdev_device(vdev->dev); | 233 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 224 | const struct mdpy_type *type = | 234 | const struct mdpy_type *type = |
| 225 | &mdpy_types[mdev_get_type_group_id(mdev)]; | 235 | container_of(mdev->type, struct mdpy_type, type); |
| 226 | u32 fbsize; | 236 | u32 fbsize; |
| 227 | int ret = -ENOMEM; | 237 | int ret = -ENOMEM; |
| 228 | 238 | ||
| @@ -655,8 +665,7 @@ static const struct attribute_group *mdev_dev_groups[] = { · 426 unmodified lines | |||
| 655 | static ssize_t name_show(struct mdev_type *mtype, | 665 | static ssize_t name_show(struct mdev_type *mtype, |
| 656 | struct mdev_type_attribute *attr, char *buf) | 666 | struct mdev_type_attribute *attr, char *buf) |
| 657 | { | 667 | { |
| 658 | const struct mdpy_type *type = | 668 | struct mdpy_type *type = container_of(mtype, struct mdpy_type, type); |
| 659 | &mdpy_types[mtype_get_type_group_id(mtype)]; | ||
| 660 | 669 | ||
| 661 | return sprintf(buf, "%s\n", type->name); | 670 | return sprintf(buf, "%s\n", type->name); |
| 662 | } | 671 | } |
| @@ -665,8 +674,7 @@ static MDEV_TYPE_ATTR_RO(name); · 2 unmodified lines | |||
| 665 | static ssize_t description_show(struct mdev_type *mtype, | 674 | static ssize_t description_show(struct mdev_type *mtype, |
| 666 | struct mdev_type_attribute *attr, char *buf) | 675 | struct mdev_type_attribute *attr, char *buf) |
| 667 | { | 676 | { |
| 668 | const struct mdpy_type *type = | 677 | struct mdpy_type *type = container_of(mtype, struct mdpy_type, type); |
| 669 | &mdpy_types[mtype_get_type_group_id(mtype)]; | ||
| 670 | 678 | ||
| 671 | return sprintf(buf, "virtual display, %dx%d framebuffer\n", | 679 | return sprintf(buf, "virtual display, %dx%d framebuffer\n", |
| 672 | type->width, type->height); | 680 | type->width, type->height); |
| @@ -688,7 +696,7 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 15 unmodified lines | |||
| 688 | } | 696 | } |
| 689 | static MDEV_TYPE_ATTR_RO(device_api); | 697 | static MDEV_TYPE_ATTR_RO(device_api); |
| 690 | 698 | ||
| 691 | static struct attribute *mdev_types_attrs[] = { | 699 | static const struct attribute *mdev_types_attrs[] = { |
| 692 | &mdev_type_attr_name.attr, | 700 | &mdev_type_attr_name.attr, |
| 693 | &mdev_type_attr_description.attr, | 701 | &mdev_type_attr_description.attr, |
| 694 | &mdev_type_attr_device_api.attr, | 702 | &mdev_type_attr_device_api.attr, |
| @@ -696,28 +704,6 @@ static struct attribute *mdev_types_attrs[] = { · 1 unmodified line | |||
| 696 | NULL, | 704 | NULL, |
| 697 | }; | 705 | }; |
| 698 | 706 | ||
| 699 | static struct attribute_group mdev_type_group1 = { | ||
| 700 | .name = MDPY_TYPE_1, | ||
| 701 | .attrs = mdev_types_attrs, | ||
| 702 | }; | ||
| 703 | |||
| 704 | static struct attribute_group mdev_type_group2 = { | ||
| 705 | .name = MDPY_TYPE_2, | ||
| 706 | .attrs = mdev_types_attrs, | ||
| 707 | }; | ||
| 708 | |||
| 709 | static struct attribute_group mdev_type_group3 = { | ||
| 710 | .name = MDPY_TYPE_3, | ||
| 711 | .attrs = mdev_types_attrs, | ||
| 712 | }; | ||
| 713 | |||
| 714 | static struct attribute_group *mdev_type_groups[] = { | ||
| 715 | &mdev_type_group1, | ||
| 716 | &mdev_type_group2, | ||
| 717 | &mdev_type_group3, | ||
| 718 | NULL, | ||
| 719 | }; | ||
| 720 | |||
| 721 | static const struct vfio_device_ops mdpy_dev_ops = { | 707 | static const struct vfio_device_ops mdpy_dev_ops = { |
| 722 | .init = mdpy_init_dev, | 708 | .init = mdpy_init_dev, |
| 723 | .release = mdpy_release_dev, | 709 | .release = mdpy_release_dev, |
| @@ -736,7 +722,7 @@ static struct mdev_driver mdpy_driver = { · 12 unmodified lines | |||
| 736 | }, | 722 | }, |
| 737 | .probe = mdpy_probe, | 723 | .probe = mdpy_probe, |
| 738 | .remove = mdpy_remove, | 724 | .remove = mdpy_remove, |
| 739 | .supported_type_groups = mdev_type_groups, | 725 | .types_attrs = mdev_types_attrs, |
| 740 | }; | 726 | }; |
| 741 | 727 | ||
| 742 | static const struct file_operations vd_fops = { | 728 | static const struct file_operations vd_fops = { |
| @@ -779,7 +765,9 @@ static int __init mdpy_dev_init(void) · 36 unmodified lines | |||
| 779 | if (ret) | 765 | if (ret) |
| 780 | goto err_class; | 766 | goto err_class; |
| 781 | 767 | ||
| 782 | ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver); | 768 | ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver, |
| 769 | mdpy_mdev_types, | ||
| 770 | ARRAY_SIZE(mdpy_mdev_types)); | ||
| 783 | if (ret) | 771 | if (ret) |
| 784 | goto err_device; | 772 | goto err_device; |
| 785 | 773 | ||
| @@ -143,6 +143,20 @@ struct mdev_state { · 142 unmodified lines | |||
| 143 | int nr_ports; | 143 | int nr_ports; |
| 144 | }; | 144 | }; |
| 145 | 145 | ||
| 146 | static struct mtty_type { | ||
| 147 | struct mdev_type type; | ||
| 148 | int nr_ports; | ||
| 149 | const char *name; | ||
| 150 | } mtty_types[2] = { | ||
| 151 | { .nr_ports = 1, .type.sysfs_name = "1", .name = "Single port serial" }, | ||
| 152 | { .nr_ports = 2, .type.sysfs_name = "2", .name = "Dual port serial" }, | ||
| 153 | }; | ||
| 154 | |||
| 155 | static struct mdev_type *mtty_mdev_types[] = { | ||
| 156 | &mtty_types[0].type, | ||
| 157 | &mtty_types[1].type, | ||
| 158 | }; | ||
| 159 | |||
| 146 | static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS); | 160 | static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS); |
| 147 | 161 | ||
| 148 | static const struct file_operations vd_fops = { | 162 | static const struct file_operations vd_fops = { |
| @@ -707,17 +721,19 @@ static int mtty_init_dev(struct vfio_device *vdev) · 558 unmodified lines | |||
| 707 | struct mdev_state *mdev_state = | 721 | struct mdev_state *mdev_state = |
| 708 | container_of(vdev, struct mdev_state, vdev); | 722 | container_of(vdev, struct mdev_state, vdev); |
| 709 | struct mdev_device *mdev = to_mdev_device(vdev->dev); | 723 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 710 | int nr_ports = mdev_get_type_group_id(mdev) + 1; | 724 | struct mtty_type *type = |
| 725 | container_of(mdev->type, struct mtty_type, type); | ||
| 711 | int avail_ports = atomic_read(&mdev_avail_ports); | 726 | int avail_ports = atomic_read(&mdev_avail_ports); |
| 712 | int ret; | 727 | int ret; |
| 713 | 728 | ||
| 714 | do { | 729 | do { |
| 715 | if (avail_ports < nr_ports) | 730 | if (avail_ports < type->nr_ports) |
| 716 | return -ENOSPC; | 731 | return -ENOSPC; |
| 717 | } while (!atomic_try_cmpxchg(&mdev_avail_ports, | 732 | } while (!atomic_try_cmpxchg(&mdev_avail_ports, |
| 718 | &avail_ports, avail_ports - nr_ports)); | 733 | &avail_ports, |
| 734 | avail_ports - type->nr_ports)); | ||
| 719 | 735 | ||
| 720 | mdev_state->nr_ports = nr_ports; | 736 | mdev_state->nr_ports = type->nr_ports; |
| 721 | mdev_state->irq_index = -1; | 737 | mdev_state->irq_index = -1; |
| 722 | mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE; | 738 | mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE; |
| 723 | mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE; | 739 | mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE; |
| @@ -735,7 +751,7 @@ static int mtty_init_dev(struct vfio_device *vdev) · 11 unmodified lines | |||
| 735 | return 0; | 751 | return 0; |
| 736 | 752 | ||
| 737 | err_nr_ports: | 753 | err_nr_ports: |
| 738 | atomic_add(nr_ports, &mdev_avail_ports); | 754 | atomic_add(type->nr_ports, &mdev_avail_ports); |
| 739 | return ret; | 755 | return ret; |
| 740 | } | 756 | } |
| 741 | 757 | ||
| @@ -1242,11 +1258,9 @@ static const struct attribute_group *mdev_dev_groups[] = { · 500 unmodified lines | |||
| 1242 | static ssize_t name_show(struct mdev_type *mtype, | 1258 | static ssize_t name_show(struct mdev_type *mtype, |
| 1243 | struct mdev_type_attribute *attr, char *buf) | 1259 | struct mdev_type_attribute *attr, char *buf) |
| 1244 | { | 1260 | { |
| 1245 | static const char *name_str[2] = { "Single port serial", | 1261 | struct mtty_type *type = container_of(mtype, struct mtty_type, type); |
| 1246 | "Dual port serial" }; | ||
| 1247 | 1262 | ||
| 1248 | return sysfs_emit(buf, "%s\n", | 1263 | return sysfs_emit(buf, "%s\n", type->name); |
| 1249 | name_str[mtype_get_type_group_id(mtype)]); | ||
| 1250 | } | 1264 | } |
| 1251 | 1265 | ||
| 1252 | static MDEV_TYPE_ATTR_RO(name); | 1266 | static MDEV_TYPE_ATTR_RO(name); |
| @@ -1255,9 +1269,10 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 2 unmodified lines | |||
| 1255 | struct mdev_type_attribute *attr, | 1269 | struct mdev_type_attribute *attr, |
| 1256 | char *buf) | 1270 | char *buf) |
| 1257 | { | 1271 | { |
| 1258 | unsigned int ports = mtype_get_type_group_id(mtype) + 1; | 1272 | struct mtty_type *type = container_of(mtype, struct mtty_type, type); |
| 1259 | 1273 | ||
| 1260 | return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / ports); | 1274 | return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / |
| 1275 | type->nr_ports); | ||
| 1261 | } | 1276 | } |
| 1262 | 1277 | ||
| 1263 | static MDEV_TYPE_ATTR_RO(available_instances); | 1278 | static MDEV_TYPE_ATTR_RO(available_instances); |
| @@ -1270,29 +1285,13 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 6 unmodified lines | |||
| 1270 | 1285 | ||
| 1271 | static MDEV_TYPE_ATTR_RO(device_api); | 1286 | static MDEV_TYPE_ATTR_RO(device_api); |
| 1272 | 1287 | ||
| 1273 | static struct attribute *mdev_types_attrs[] = { | 1288 | static const struct attribute *mdev_types_attrs[] = { |
| 1274 | &mdev_type_attr_name.attr, | 1289 | &mdev_type_attr_name.attr, |
| 1275 | &mdev_type_attr_device_api.attr, | 1290 | &mdev_type_attr_device_api.attr, |
| 1276 | &mdev_type_attr_available_instances.attr, | 1291 | &mdev_type_attr_available_instances.attr, |
| 1277 | NULL, | 1292 | NULL, |
| 1278 | }; | 1293 | }; |
| 1279 | 1294 | ||
| 1280 | static struct attribute_group mdev_type_group1 = { | ||
| 1281 | .name = "1", | ||
| 1282 | .attrs = mdev_types_attrs, | ||
| 1283 | }; | ||
| 1284 | |||
| 1285 | static struct attribute_group mdev_type_group2 = { | ||
| 1286 | .name = "2", | ||
| 1287 | .attrs = mdev_types_attrs, | ||
| 1288 | }; | ||
| 1289 | |||
| 1290 | static struct attribute_group *mdev_type_groups[] = { | ||
| 1291 | &mdev_type_group1, | ||
| 1292 | &mdev_type_group2, | ||
| 1293 | NULL, | ||
| 1294 | }; | ||
| 1295 | |||
| 1296 | static const struct vfio_device_ops mtty_dev_ops = { | 1295 | static const struct vfio_device_ops mtty_dev_ops = { |
| 1297 | .name = "vfio-mtty", | 1296 | .name = "vfio-mtty", |
| 1298 | .init = mtty_init_dev, | 1297 | .init = mtty_init_dev, |
| @@ -1311,7 +1310,7 @@ static struct mdev_driver mtty_driver = { · 12 unmodified lines | |||
| 1311 | }, | 1310 | }, |
| 1312 | .probe = mtty_probe, | 1311 | .probe = mtty_probe, |
| 1313 | .remove = mtty_remove, | 1312 | .remove = mtty_remove, |
| 1314 | .supported_type_groups = mdev_type_groups, | 1313 | .types_attrs = mdev_types_attrs, |
| 1315 | }; | 1314 | }; |
| 1316 | 1315 | ||
| 1317 | static void mtty_device_release(struct device *dev) | 1316 | static void mtty_device_release(struct device *dev) |
| @@ -1363,7 +1362,8 @@ static int __init mtty_dev_init(void) · 45 unmodified lines | |||
| 1363 | goto err_class; | 1362 | goto err_class; |
| 1364 | 1363 | ||
| 1365 | ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev, | 1364 | ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev, |
| 1366 | &mtty_driver); | 1365 | &mtty_driver, mtty_mdev_types, |
| 1366 | ARRAY_SIZE(mtty_mdev_types)); | ||
| 1367 | if (ret) | 1367 | if (ret) |
| 1368 | goto err_device; | 1368 | goto err_device; |
| 1369 | return 0; | 1369 | return 0; |