xref: /linux/drivers/gpu/drm/vkms/vkms_configfs.c (revision 815e260a18a3af4dab59025ee99a7156c0e8b5e0)
1 // SPDX-License-Identifier: GPL-2.0+
2 #include <linux/cleanup.h>
3 #include <linux/configfs.h>
4 #include <linux/mutex.h>
5 #include <linux/slab.h>
6 
7 #include "vkms_drv.h"
8 #include "vkms_config.h"
9 #include "vkms_configfs.h"
10 #include "vkms_connector.h"
11 
12 /* To avoid registering configfs more than once or unregistering on error */
13 static bool is_configfs_registered;
14 
15 /**
16  * struct vkms_configfs_device - Configfs representation of a VKMS device
17  *
18  * @group: Top level configuration group that represents a VKMS device.
19  * Initialized when a new directory is created under "/config/vkms/"
20  * @planes_group: Default subgroup of @group at "/config/vkms/planes"
21  * @crtcs_group: Default subgroup of @group at "/config/vkms/crtcs"
22  * @encoders_group: Default subgroup of @group at "/config/vkms/encoders"
23  * @connectors_group: Default subgroup of @group at "/config/vkms/connectors"
24  * @lock: Lock used to project concurrent access to the configuration attributes
25  * @config: Protected by @lock. Configuration of the VKMS device
26  * @enabled: Protected by @lock. The device is created or destroyed when this
27  * option changes
28  */
29 struct vkms_configfs_device {
30 	struct config_group group;
31 	struct config_group planes_group;
32 	struct config_group crtcs_group;
33 	struct config_group encoders_group;
34 	struct config_group connectors_group;
35 
36 	struct mutex lock;
37 	struct vkms_config *config;
38 	bool enabled;
39 };
40 
41 /**
42  * struct vkms_configfs_plane - Configfs representation of a plane
43  *
44  * @group: Top level configuration group that represents a plane.
45  * Initialized when a new directory is created under "/config/vkms/planes"
46  * @possible_crtcs_group: Default subgroup of @group at "plane/possible_crtcs"
47  * @dev: The vkms_configfs_device this plane belongs to
48  * @config: Configuration of the VKMS plane
49  */
50 struct vkms_configfs_plane {
51 	struct config_group group;
52 	struct config_group possible_crtcs_group;
53 	struct vkms_configfs_device *dev;
54 	struct vkms_config_plane *config;
55 };
56 
57 /**
58  * struct vkms_configfs_crtc - Configfs representation of a CRTC
59  *
60  * @group: Top level configuration group that represents a CRTC.
61  * Initialized when a new directory is created under "/config/vkms/crtcs"
62  * @dev: The vkms_configfs_device this CRTC belongs to
63  * @config: Configuration of the VKMS CRTC
64  */
65 struct vkms_configfs_crtc {
66 	struct config_group group;
67 	struct vkms_configfs_device *dev;
68 	struct vkms_config_crtc *config;
69 };
70 
71 /**
72  * struct vkms_configfs_encoder - Configfs representation of a encoder
73  *
74  * @group: Top level configuration group that represents a encoder.
75  * Initialized when a new directory is created under "/config/vkms/encoders"
76  * @possible_crtcs_group: Default subgroup of @group at "encoder/possible_crtcs"
77  * @dev: The vkms_configfs_device this encoder belongs to
78  * @config: Configuration of the VKMS encoder
79  */
80 struct vkms_configfs_encoder {
81 	struct config_group group;
82 	struct config_group possible_crtcs_group;
83 	struct vkms_configfs_device *dev;
84 	struct vkms_config_encoder *config;
85 };
86 
87 /**
88  * struct vkms_configfs_connector - Configfs representation of a connector
89  *
90  * @group: Top level configuration group that represents a connector.
91  * Initialized when a new directory is created under "/config/vkms/connectors"
92  * @possible_encoders_group: Default subgroup of @group at
93  * "connector/possible_encoders"
94  * @dev: The vkms_configfs_device this connector belongs to
95  * @config: Configuration of the VKMS connector
96  */
97 struct vkms_configfs_connector {
98 	struct config_group group;
99 	struct config_group possible_encoders_group;
100 	struct vkms_configfs_device *dev;
101 	struct vkms_config_connector *config;
102 };
103 
104 #define device_item_to_vkms_configfs_device(item) \
105 	container_of(to_config_group((item)), struct vkms_configfs_device, \
106 		     group)
107 
108 #define child_group_to_vkms_configfs_device(group) \
109 	device_item_to_vkms_configfs_device((&(group)->cg_item)->ci_parent)
110 
111 #define plane_item_to_vkms_configfs_plane(item) \
112 	container_of(to_config_group((item)), struct vkms_configfs_plane, group)
113 
114 #define plane_possible_crtcs_item_to_vkms_configfs_plane(item) \
115 	container_of(to_config_group((item)), struct vkms_configfs_plane, \
116 		     possible_crtcs_group)
117 
118 #define crtc_item_to_vkms_configfs_crtc(item) \
119 	container_of(to_config_group((item)), struct vkms_configfs_crtc, group)
120 
121 #define encoder_item_to_vkms_configfs_encoder(item) \
122 	container_of(to_config_group((item)), struct vkms_configfs_encoder, \
123 		     group)
124 
125 #define encoder_possible_crtcs_item_to_vkms_configfs_encoder(item) \
126 	container_of(to_config_group((item)), struct vkms_configfs_encoder, \
127 		     possible_crtcs_group)
128 
129 #define connector_item_to_vkms_configfs_connector(item) \
130 	container_of(to_config_group((item)), struct vkms_configfs_connector, \
131 		     group)
132 
133 #define connector_possible_encoders_item_to_vkms_configfs_connector(item) \
134 	container_of(to_config_group((item)), struct vkms_configfs_connector, \
135 		     possible_encoders_group)
136 
137 static ssize_t crtc_writeback_show(struct config_item *item, char *page)
138 {
139 	struct vkms_configfs_crtc *crtc;
140 	bool writeback;
141 
142 	crtc = crtc_item_to_vkms_configfs_crtc(item);
143 
144 	scoped_guard(mutex, &crtc->dev->lock)
145 		writeback = vkms_config_crtc_get_writeback(crtc->config);
146 
147 	return sprintf(page, "%d\n", writeback);
148 }
149 
150 static ssize_t crtc_writeback_store(struct config_item *item, const char *page,
151 				    size_t count)
152 {
153 	struct vkms_configfs_crtc *crtc;
154 	bool writeback;
155 
156 	crtc = crtc_item_to_vkms_configfs_crtc(item);
157 
158 	if (kstrtobool(page, &writeback))
159 		return -EINVAL;
160 
161 	scoped_guard(mutex, &crtc->dev->lock) {
162 		if (crtc->dev->enabled)
163 			return -EBUSY;
164 
165 		vkms_config_crtc_set_writeback(crtc->config, writeback);
166 	}
167 
168 	return (ssize_t)count;
169 }
170 
171 CONFIGFS_ATTR(crtc_, writeback);
172 
173 static struct configfs_attribute *crtc_item_attrs[] = {
174 	&crtc_attr_writeback,
175 	NULL,
176 };
177 
178 static void crtc_release(struct config_item *item)
179 {
180 	struct vkms_configfs_crtc *crtc;
181 	struct mutex *lock;
182 
183 	crtc = crtc_item_to_vkms_configfs_crtc(item);
184 	lock = &crtc->dev->lock;
185 
186 	scoped_guard(mutex, lock) {
187 		vkms_config_destroy_crtc(crtc->dev->config, crtc->config);
188 		kfree(crtc);
189 	}
190 }
191 
192 static struct configfs_item_operations crtc_item_operations = {
193 	.release	= &crtc_release,
194 };
195 
196 static const struct config_item_type crtc_item_type = {
197 	.ct_attrs	= crtc_item_attrs,
198 	.ct_item_ops	= &crtc_item_operations,
199 	.ct_owner	= THIS_MODULE,
200 };
201 
202 static struct config_group *make_crtc_group(struct config_group *group,
203 					    const char *name)
204 {
205 	struct vkms_configfs_device *dev;
206 	struct vkms_configfs_crtc *crtc;
207 	int ret;
208 
209 	dev = child_group_to_vkms_configfs_device(group);
210 
211 	scoped_guard(mutex, &dev->lock) {
212 		if (dev->enabled)
213 			return ERR_PTR(-EBUSY);
214 
215 		crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
216 		if (!crtc)
217 			return ERR_PTR(-ENOMEM);
218 
219 		crtc->dev = dev;
220 
221 		crtc->config = vkms_config_create_crtc(dev->config);
222 		if (IS_ERR(crtc->config)) {
223 			ret = PTR_ERR(crtc->config);
224 			kfree(crtc);
225 			return ERR_PTR(ret);
226 		}
227 
228 		config_group_init_type_name(&crtc->group, name, &crtc_item_type);
229 	}
230 
231 	return &crtc->group;
232 }
233 
234 static struct configfs_group_operations crtcs_group_operations = {
235 	.make_group	= &make_crtc_group,
236 };
237 
238 static const struct config_item_type crtc_group_type = {
239 	.ct_group_ops	= &crtcs_group_operations,
240 	.ct_owner	= THIS_MODULE,
241 };
242 
243 static int plane_possible_crtcs_allow_link(struct config_item *src,
244 					   struct config_item *target)
245 {
246 	struct vkms_configfs_plane *plane;
247 	struct vkms_configfs_crtc *crtc;
248 	int ret;
249 
250 	if (target->ci_type != &crtc_item_type)
251 		return -EINVAL;
252 
253 	plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src);
254 	crtc = crtc_item_to_vkms_configfs_crtc(target);
255 
256 	scoped_guard(mutex, &plane->dev->lock) {
257 		if (plane->dev->enabled)
258 			return -EBUSY;
259 
260 		ret = vkms_config_plane_attach_crtc(plane->config, crtc->config);
261 	}
262 
263 	return ret;
264 }
265 
266 static void plane_possible_crtcs_drop_link(struct config_item *src,
267 					   struct config_item *target)
268 {
269 	struct vkms_configfs_plane *plane;
270 	struct vkms_configfs_crtc *crtc;
271 
272 	plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src);
273 	crtc = crtc_item_to_vkms_configfs_crtc(target);
274 
275 	scoped_guard(mutex, &plane->dev->lock)
276 		vkms_config_plane_detach_crtc(plane->config, crtc->config);
277 }
278 
279 static struct configfs_item_operations plane_possible_crtcs_item_operations = {
280 	.allow_link	= plane_possible_crtcs_allow_link,
281 	.drop_link	= plane_possible_crtcs_drop_link,
282 };
283 
284 static const struct config_item_type plane_possible_crtcs_group_type = {
285 	.ct_item_ops	= &plane_possible_crtcs_item_operations,
286 	.ct_owner	= THIS_MODULE,
287 };
288 
289 static ssize_t plane_type_show(struct config_item *item, char *page)
290 {
291 	struct vkms_configfs_plane *plane;
292 	enum drm_plane_type type;
293 
294 	plane = plane_item_to_vkms_configfs_plane(item);
295 
296 	scoped_guard(mutex, &plane->dev->lock)
297 		type = vkms_config_plane_get_type(plane->config);
298 
299 	return sprintf(page, "%u", type);
300 }
301 
302 static ssize_t plane_type_store(struct config_item *item, const char *page,
303 				size_t count)
304 {
305 	struct vkms_configfs_plane *plane;
306 	enum drm_plane_type type;
307 
308 	plane = plane_item_to_vkms_configfs_plane(item);
309 
310 	if (kstrtouint(page, 10, &type))
311 		return -EINVAL;
312 
313 	if (type != DRM_PLANE_TYPE_OVERLAY && type != DRM_PLANE_TYPE_PRIMARY &&
314 	    type != DRM_PLANE_TYPE_CURSOR)
315 		return -EINVAL;
316 
317 	scoped_guard(mutex, &plane->dev->lock) {
318 		if (plane->dev->enabled)
319 			return -EBUSY;
320 
321 		vkms_config_plane_set_type(plane->config, type);
322 	}
323 
324 	return (ssize_t)count;
325 }
326 
327 CONFIGFS_ATTR(plane_, type);
328 
329 static struct configfs_attribute *plane_item_attrs[] = {
330 	&plane_attr_type,
331 	NULL,
332 };
333 
334 static void plane_release(struct config_item *item)
335 {
336 	struct vkms_configfs_plane *plane;
337 	struct mutex *lock;
338 
339 	plane = plane_item_to_vkms_configfs_plane(item);
340 	lock = &plane->dev->lock;
341 
342 	scoped_guard(mutex, lock) {
343 		vkms_config_destroy_plane(plane->config);
344 		kfree(plane);
345 	}
346 }
347 
348 static struct configfs_item_operations plane_item_operations = {
349 	.release	= &plane_release,
350 };
351 
352 static const struct config_item_type plane_item_type = {
353 	.ct_attrs	= plane_item_attrs,
354 	.ct_item_ops	= &plane_item_operations,
355 	.ct_owner	= THIS_MODULE,
356 };
357 
358 static struct config_group *make_plane_group(struct config_group *group,
359 					     const char *name)
360 {
361 	struct vkms_configfs_device *dev;
362 	struct vkms_configfs_plane *plane;
363 	int ret;
364 
365 	dev = child_group_to_vkms_configfs_device(group);
366 
367 	scoped_guard(mutex, &dev->lock) {
368 		if (dev->enabled)
369 			return ERR_PTR(-EBUSY);
370 
371 		plane = kzalloc(sizeof(*plane), GFP_KERNEL);
372 		if (!plane)
373 			return ERR_PTR(-ENOMEM);
374 
375 		plane->dev = dev;
376 
377 		plane->config = vkms_config_create_plane(dev->config);
378 		if (IS_ERR(plane->config)) {
379 			ret = PTR_ERR(plane->config);
380 			kfree(plane);
381 			return ERR_PTR(ret);
382 		}
383 
384 		config_group_init_type_name(&plane->group, name, &plane_item_type);
385 
386 		config_group_init_type_name(&plane->possible_crtcs_group,
387 					    "possible_crtcs",
388 					    &plane_possible_crtcs_group_type);
389 		configfs_add_default_group(&plane->possible_crtcs_group,
390 					   &plane->group);
391 	}
392 
393 	return &plane->group;
394 }
395 
396 static struct configfs_group_operations planes_group_operations = {
397 	.make_group	= &make_plane_group,
398 };
399 
400 static const struct config_item_type plane_group_type = {
401 	.ct_group_ops	= &planes_group_operations,
402 	.ct_owner	= THIS_MODULE,
403 };
404 
405 static int encoder_possible_crtcs_allow_link(struct config_item *src,
406 					     struct config_item *target)
407 {
408 	struct vkms_configfs_encoder *encoder;
409 	struct vkms_configfs_crtc *crtc;
410 	int ret;
411 
412 	if (target->ci_type != &crtc_item_type)
413 		return -EINVAL;
414 
415 	encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src);
416 	crtc = crtc_item_to_vkms_configfs_crtc(target);
417 
418 	scoped_guard(mutex, &encoder->dev->lock) {
419 		if (encoder->dev->enabled)
420 			return -EBUSY;
421 
422 		ret = vkms_config_encoder_attach_crtc(encoder->config, crtc->config);
423 	}
424 
425 	return ret;
426 }
427 
428 static void encoder_possible_crtcs_drop_link(struct config_item *src,
429 					     struct config_item *target)
430 {
431 	struct vkms_configfs_encoder *encoder;
432 	struct vkms_configfs_crtc *crtc;
433 
434 	encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src);
435 	crtc = crtc_item_to_vkms_configfs_crtc(target);
436 
437 	scoped_guard(mutex, &encoder->dev->lock)
438 		vkms_config_encoder_detach_crtc(encoder->config, crtc->config);
439 }
440 
441 static struct configfs_item_operations encoder_possible_crtcs_item_operations = {
442 	.allow_link	= encoder_possible_crtcs_allow_link,
443 	.drop_link	= encoder_possible_crtcs_drop_link,
444 };
445 
446 static const struct config_item_type encoder_possible_crtcs_group_type = {
447 	.ct_item_ops	= &encoder_possible_crtcs_item_operations,
448 	.ct_owner	= THIS_MODULE,
449 };
450 
451 static void encoder_release(struct config_item *item)
452 {
453 	struct vkms_configfs_encoder *encoder;
454 	struct mutex *lock;
455 
456 	encoder = encoder_item_to_vkms_configfs_encoder(item);
457 	lock = &encoder->dev->lock;
458 
459 	scoped_guard(mutex, lock) {
460 		vkms_config_destroy_encoder(encoder->dev->config, encoder->config);
461 		kfree(encoder);
462 	}
463 }
464 
465 static struct configfs_item_operations encoder_item_operations = {
466 	.release	= &encoder_release,
467 };
468 
469 static const struct config_item_type encoder_item_type = {
470 	.ct_item_ops	= &encoder_item_operations,
471 	.ct_owner	= THIS_MODULE,
472 };
473 
474 static struct config_group *make_encoder_group(struct config_group *group,
475 					       const char *name)
476 {
477 	struct vkms_configfs_device *dev;
478 	struct vkms_configfs_encoder *encoder;
479 	int ret;
480 
481 	dev = child_group_to_vkms_configfs_device(group);
482 
483 	scoped_guard(mutex, &dev->lock) {
484 		if (dev->enabled)
485 			return ERR_PTR(-EBUSY);
486 
487 		encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
488 		if (!encoder)
489 			return ERR_PTR(-ENOMEM);
490 
491 		encoder->dev = dev;
492 
493 		encoder->config = vkms_config_create_encoder(dev->config);
494 		if (IS_ERR(encoder->config)) {
495 			ret = PTR_ERR(encoder->config);
496 			kfree(encoder);
497 			return ERR_PTR(ret);
498 		}
499 
500 		config_group_init_type_name(&encoder->group, name,
501 					    &encoder_item_type);
502 
503 		config_group_init_type_name(&encoder->possible_crtcs_group,
504 					    "possible_crtcs",
505 					    &encoder_possible_crtcs_group_type);
506 		configfs_add_default_group(&encoder->possible_crtcs_group,
507 					   &encoder->group);
508 	}
509 
510 	return &encoder->group;
511 }
512 
513 static struct configfs_group_operations encoders_group_operations = {
514 	.make_group	= &make_encoder_group,
515 };
516 
517 static const struct config_item_type encoder_group_type = {
518 	.ct_group_ops	= &encoders_group_operations,
519 	.ct_owner	= THIS_MODULE,
520 };
521 
522 static ssize_t connector_status_show(struct config_item *item, char *page)
523 {
524 	struct vkms_configfs_connector *connector;
525 	enum drm_connector_status status;
526 
527 	connector = connector_item_to_vkms_configfs_connector(item);
528 
529 	scoped_guard(mutex, &connector->dev->lock)
530 		status = vkms_config_connector_get_status(connector->config);
531 
532 	return sprintf(page, "%u", status);
533 }
534 
535 static ssize_t connector_status_store(struct config_item *item,
536 				      const char *page, size_t count)
537 {
538 	struct vkms_configfs_connector *connector;
539 	enum drm_connector_status status;
540 
541 	connector = connector_item_to_vkms_configfs_connector(item);
542 
543 	if (kstrtouint(page, 10, &status))
544 		return -EINVAL;
545 
546 	if (status != connector_status_connected &&
547 	    status != connector_status_disconnected &&
548 	    status != connector_status_unknown)
549 		return -EINVAL;
550 
551 	scoped_guard(mutex, &connector->dev->lock) {
552 		vkms_config_connector_set_status(connector->config, status);
553 
554 		if (connector->dev->enabled)
555 			vkms_trigger_connector_hotplug(connector->dev->config->dev);
556 	}
557 
558 	return (ssize_t)count;
559 }
560 
561 CONFIGFS_ATTR(connector_, status);
562 
563 static struct configfs_attribute *connector_item_attrs[] = {
564 	&connector_attr_status,
565 	NULL,
566 };
567 
568 static void connector_release(struct config_item *item)
569 {
570 	struct vkms_configfs_connector *connector;
571 	struct mutex *lock;
572 
573 	connector = connector_item_to_vkms_configfs_connector(item);
574 	lock = &connector->dev->lock;
575 
576 	scoped_guard(mutex, lock) {
577 		vkms_config_destroy_connector(connector->config);
578 		kfree(connector);
579 	}
580 }
581 
582 static struct configfs_item_operations connector_item_operations = {
583 	.release	= &connector_release,
584 };
585 
586 static const struct config_item_type connector_item_type = {
587 	.ct_attrs	= connector_item_attrs,
588 	.ct_item_ops	= &connector_item_operations,
589 	.ct_owner	= THIS_MODULE,
590 };
591 
592 static int connector_possible_encoders_allow_link(struct config_item *src,
593 						  struct config_item *target)
594 {
595 	struct vkms_configfs_connector *connector;
596 	struct vkms_configfs_encoder *encoder;
597 	int ret;
598 
599 	if (target->ci_type != &encoder_item_type)
600 		return -EINVAL;
601 
602 	connector = connector_possible_encoders_item_to_vkms_configfs_connector(src);
603 	encoder = encoder_item_to_vkms_configfs_encoder(target);
604 
605 	scoped_guard(mutex, &connector->dev->lock) {
606 		if (connector->dev->enabled)
607 			return -EBUSY;
608 
609 		ret = vkms_config_connector_attach_encoder(connector->config,
610 							   encoder->config);
611 	}
612 
613 	return ret;
614 }
615 
616 static void connector_possible_encoders_drop_link(struct config_item *src,
617 						  struct config_item *target)
618 {
619 	struct vkms_configfs_connector *connector;
620 	struct vkms_configfs_encoder *encoder;
621 
622 	connector = connector_possible_encoders_item_to_vkms_configfs_connector(src);
623 	encoder = encoder_item_to_vkms_configfs_encoder(target);
624 
625 	scoped_guard(mutex, &connector->dev->lock) {
626 		vkms_config_connector_detach_encoder(connector->config,
627 						     encoder->config);
628 	}
629 }
630 
631 static struct configfs_item_operations connector_possible_encoders_item_operations = {
632 	.allow_link	= connector_possible_encoders_allow_link,
633 	.drop_link	= connector_possible_encoders_drop_link,
634 };
635 
636 static const struct config_item_type connector_possible_encoders_group_type = {
637 	.ct_item_ops	= &connector_possible_encoders_item_operations,
638 	.ct_owner	= THIS_MODULE,
639 };
640 
641 static struct config_group *make_connector_group(struct config_group *group,
642 						 const char *name)
643 {
644 	struct vkms_configfs_device *dev;
645 	struct vkms_configfs_connector *connector;
646 	int ret;
647 
648 	dev = child_group_to_vkms_configfs_device(group);
649 
650 	scoped_guard(mutex, &dev->lock) {
651 		if (dev->enabled)
652 			return ERR_PTR(-EBUSY);
653 
654 		connector = kzalloc(sizeof(*connector), GFP_KERNEL);
655 		if (!connector)
656 			return ERR_PTR(-ENOMEM);
657 
658 		connector->dev = dev;
659 
660 		connector->config = vkms_config_create_connector(dev->config);
661 		if (IS_ERR(connector->config)) {
662 			ret = PTR_ERR(connector->config);
663 			kfree(connector);
664 			return ERR_PTR(ret);
665 		}
666 
667 		config_group_init_type_name(&connector->group, name,
668 					    &connector_item_type);
669 
670 		config_group_init_type_name(&connector->possible_encoders_group,
671 					    "possible_encoders",
672 					    &connector_possible_encoders_group_type);
673 		configfs_add_default_group(&connector->possible_encoders_group,
674 					   &connector->group);
675 	}
676 
677 	return &connector->group;
678 }
679 
680 static struct configfs_group_operations connectors_group_operations = {
681 	.make_group	= &make_connector_group,
682 };
683 
684 static const struct config_item_type connector_group_type = {
685 	.ct_group_ops	= &connectors_group_operations,
686 	.ct_owner	= THIS_MODULE,
687 };
688 
689 static ssize_t device_enabled_show(struct config_item *item, char *page)
690 {
691 	struct vkms_configfs_device *dev;
692 	bool enabled;
693 
694 	dev = device_item_to_vkms_configfs_device(item);
695 
696 	scoped_guard(mutex, &dev->lock)
697 		enabled = dev->enabled;
698 
699 	return sprintf(page, "%d\n", enabled);
700 }
701 
702 static ssize_t device_enabled_store(struct config_item *item, const char *page,
703 				    size_t count)
704 {
705 	struct vkms_configfs_device *dev;
706 	bool enabled;
707 	int ret = 0;
708 
709 	dev = device_item_to_vkms_configfs_device(item);
710 
711 	if (kstrtobool(page, &enabled))
712 		return -EINVAL;
713 
714 	scoped_guard(mutex, &dev->lock) {
715 		if (!dev->enabled && enabled) {
716 			if (!vkms_config_is_valid(dev->config))
717 				return -EINVAL;
718 
719 			ret = vkms_create(dev->config);
720 			if (ret)
721 				return ret;
722 		} else if (dev->enabled && !enabled) {
723 			vkms_destroy(dev->config);
724 		}
725 
726 		dev->enabled = enabled;
727 	}
728 
729 	return (ssize_t)count;
730 }
731 
732 CONFIGFS_ATTR(device_, enabled);
733 
734 static struct configfs_attribute *device_item_attrs[] = {
735 	&device_attr_enabled,
736 	NULL,
737 };
738 
739 static void device_release(struct config_item *item)
740 {
741 	struct vkms_configfs_device *dev;
742 
743 	dev = device_item_to_vkms_configfs_device(item);
744 
745 	if (dev->enabled)
746 		vkms_destroy(dev->config);
747 
748 	mutex_destroy(&dev->lock);
749 	vkms_config_destroy(dev->config);
750 	kfree(dev);
751 }
752 
753 static struct configfs_item_operations device_item_operations = {
754 	.release	= &device_release,
755 };
756 
757 static const struct config_item_type device_item_type = {
758 	.ct_attrs	= device_item_attrs,
759 	.ct_item_ops	= &device_item_operations,
760 	.ct_owner	= THIS_MODULE,
761 };
762 
763 static struct config_group *make_device_group(struct config_group *group,
764 					      const char *name)
765 {
766 	struct vkms_configfs_device *dev;
767 	int ret;
768 
769 	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
770 		return ERR_PTR(-EINVAL);
771 
772 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
773 	if (!dev)
774 		return ERR_PTR(-ENOMEM);
775 
776 	dev->config = vkms_config_create(name);
777 	if (IS_ERR(dev->config)) {
778 		ret = PTR_ERR(dev->config);
779 		kfree(dev);
780 		return ERR_PTR(ret);
781 	}
782 
783 	config_group_init_type_name(&dev->group, name, &device_item_type);
784 	mutex_init(&dev->lock);
785 
786 	config_group_init_type_name(&dev->planes_group, "planes",
787 				    &plane_group_type);
788 	configfs_add_default_group(&dev->planes_group, &dev->group);
789 
790 	config_group_init_type_name(&dev->crtcs_group, "crtcs",
791 				    &crtc_group_type);
792 	configfs_add_default_group(&dev->crtcs_group, &dev->group);
793 
794 	config_group_init_type_name(&dev->encoders_group, "encoders",
795 				    &encoder_group_type);
796 	configfs_add_default_group(&dev->encoders_group, &dev->group);
797 
798 	config_group_init_type_name(&dev->connectors_group, "connectors",
799 				    &connector_group_type);
800 	configfs_add_default_group(&dev->connectors_group, &dev->group);
801 
802 	return &dev->group;
803 }
804 
805 static struct configfs_group_operations device_group_ops = {
806 	.make_group = &make_device_group,
807 };
808 
809 static const struct config_item_type device_group_type = {
810 	.ct_group_ops	= &device_group_ops,
811 	.ct_owner	= THIS_MODULE,
812 };
813 
814 static struct configfs_subsystem vkms_subsys = {
815 	.su_group = {
816 		.cg_item = {
817 			.ci_name = "vkms",
818 			.ci_type = &device_group_type,
819 		},
820 	},
821 	.su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex),
822 };
823 
824 int vkms_configfs_register(void)
825 {
826 	int ret;
827 
828 	if (is_configfs_registered)
829 		return 0;
830 
831 	config_group_init(&vkms_subsys.su_group);
832 	ret = configfs_register_subsystem(&vkms_subsys);
833 
834 	is_configfs_registered = ret == 0;
835 
836 	return ret;
837 }
838 
839 void vkms_configfs_unregister(void)
840 {
841 	if (is_configfs_registered)
842 		configfs_unregister_subsystem(&vkms_subsys);
843 }
844