Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Intel Corporation
3 : : *
4 : : * Permission to use, copy, modify, distribute, and sell this software and its
5 : : * documentation for any purpose is hereby granted without fee, provided that
6 : : * the above copyright notice appear in all copies and that both that copyright
7 : : * notice and this permission notice appear in supporting documentation, and
8 : : * that the name of the copyright holders not be used in advertising or
9 : : * publicity pertaining to distribution of the software without specific,
10 : : * written prior permission. The copyright holders make no representations
11 : : * about the suitability of this software for any purpose. It is provided "as
12 : : * is" without express or implied warranty.
13 : : *
14 : : * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 : : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 : : * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 : : * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 : : * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 : : * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 : : * OF THIS SOFTWARE.
21 : : */
22 : :
23 : : #include <linux/uaccess.h>
24 : :
25 : : #include <drm/drm_drv.h>
26 : : #include <drm/drm_encoder.h>
27 : : #include <drm/drm_file.h>
28 : : #include <drm/drm_mode_config.h>
29 : : #include <drm/drm_print.h>
30 : : #include <linux/dma-resv.h>
31 : :
32 : : #include "drm_crtc_internal.h"
33 : : #include "drm_internal.h"
34 : :
35 : 0 : int drm_modeset_register_all(struct drm_device *dev)
36 : : {
37 : 0 : int ret;
38 : :
39 : 0 : ret = drm_plane_register_all(dev);
40 [ # # ]: 0 : if (ret)
41 : 0 : goto err_plane;
42 : :
43 : 0 : ret = drm_crtc_register_all(dev);
44 [ # # ]: 0 : if (ret)
45 : 0 : goto err_crtc;
46 : :
47 : 0 : ret = drm_encoder_register_all(dev);
48 [ # # ]: 0 : if (ret)
49 : 0 : goto err_encoder;
50 : :
51 : 0 : ret = drm_connector_register_all(dev);
52 [ # # ]: 0 : if (ret)
53 : 0 : goto err_connector;
54 : :
55 : : return 0;
56 : :
57 : : err_connector:
58 : 0 : drm_encoder_unregister_all(dev);
59 : 0 : err_encoder:
60 : 0 : drm_crtc_unregister_all(dev);
61 : 0 : err_crtc:
62 : 0 : drm_plane_unregister_all(dev);
63 : : err_plane:
64 : : return ret;
65 : : }
66 : :
67 : 0 : void drm_modeset_unregister_all(struct drm_device *dev)
68 : : {
69 : 0 : drm_connector_unregister_all(dev);
70 : 0 : drm_encoder_unregister_all(dev);
71 : 0 : drm_crtc_unregister_all(dev);
72 : 0 : drm_plane_unregister_all(dev);
73 : 0 : }
74 : :
75 : : /**
76 : : * drm_mode_getresources - get graphics configuration
77 : : * @dev: drm device for the ioctl
78 : : * @data: data pointer for the ioctl
79 : : * @file_priv: drm file for the ioctl call
80 : : *
81 : : * Construct a set of configuration description structures and return
82 : : * them to the user, including CRTC, connector and framebuffer configuration.
83 : : *
84 : : * Called by the user via ioctl.
85 : : *
86 : : * Returns:
87 : : * Zero on success, negative errno on failure.
88 : : */
89 : 0 : int drm_mode_getresources(struct drm_device *dev, void *data,
90 : : struct drm_file *file_priv)
91 : : {
92 : 0 : struct drm_mode_card_res *card_res = data;
93 : 0 : struct drm_framebuffer *fb;
94 : 0 : struct drm_connector *connector;
95 : 0 : struct drm_crtc *crtc;
96 : 0 : struct drm_encoder *encoder;
97 : 0 : int count, ret = 0;
98 : 0 : uint32_t __user *fb_id;
99 : 0 : uint32_t __user *crtc_id;
100 : 0 : uint32_t __user *connector_id;
101 : 0 : uint32_t __user *encoder_id;
102 : 0 : struct drm_connector_list_iter conn_iter;
103 : :
104 [ # # ]: 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
105 : : return -EOPNOTSUPP;
106 : :
107 : 0 : mutex_lock(&file_priv->fbs_lock);
108 : 0 : count = 0;
109 : 0 : fb_id = u64_to_user_ptr(card_res->fb_id_ptr);
110 [ # # ]: 0 : list_for_each_entry(fb, &file_priv->fbs, filp_head) {
111 [ # # ]: 0 : if (count < card_res->count_fbs &&
112 [ # # ]: 0 : put_user(fb->base.id, fb_id + count)) {
113 : 0 : mutex_unlock(&file_priv->fbs_lock);
114 : 0 : return -EFAULT;
115 : : }
116 : 0 : count++;
117 : : }
118 : 0 : card_res->count_fbs = count;
119 : 0 : mutex_unlock(&file_priv->fbs_lock);
120 : :
121 : 0 : card_res->max_height = dev->mode_config.max_height;
122 : 0 : card_res->min_height = dev->mode_config.min_height;
123 : 0 : card_res->max_width = dev->mode_config.max_width;
124 : 0 : card_res->min_width = dev->mode_config.min_width;
125 : :
126 : 0 : count = 0;
127 : 0 : crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
128 [ # # ]: 0 : drm_for_each_crtc(crtc, dev) {
129 [ # # ]: 0 : if (drm_lease_held(file_priv, crtc->base.id)) {
130 [ # # ]: 0 : if (count < card_res->count_crtcs &&
131 [ # # ]: 0 : put_user(crtc->base.id, crtc_id + count))
132 : : return -EFAULT;
133 : 0 : count++;
134 : : }
135 : : }
136 : 0 : card_res->count_crtcs = count;
137 : :
138 : 0 : count = 0;
139 : 0 : encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
140 [ # # ]: 0 : drm_for_each_encoder(encoder, dev) {
141 [ # # ]: 0 : if (count < card_res->count_encoders &&
142 [ # # ]: 0 : put_user(encoder->base.id, encoder_id + count))
143 : : return -EFAULT;
144 : 0 : count++;
145 : : }
146 : 0 : card_res->count_encoders = count;
147 : :
148 : 0 : drm_connector_list_iter_begin(dev, &conn_iter);
149 : 0 : count = 0;
150 : 0 : connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
151 [ # # ]: 0 : drm_for_each_connector_iter(connector, &conn_iter) {
152 : : /* only expose writeback connectors if userspace understands them */
153 [ # # ]: 0 : if (!file_priv->writeback_connectors &&
154 [ # # ]: 0 : (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
155 : 0 : continue;
156 : :
157 [ # # ]: 0 : if (drm_lease_held(file_priv, connector->base.id)) {
158 [ # # ]: 0 : if (count < card_res->count_connectors &&
159 [ # # ]: 0 : put_user(connector->base.id, connector_id + count)) {
160 : 0 : drm_connector_list_iter_end(&conn_iter);
161 : 0 : return -EFAULT;
162 : : }
163 : 0 : count++;
164 : : }
165 : : }
166 : 0 : card_res->count_connectors = count;
167 : 0 : drm_connector_list_iter_end(&conn_iter);
168 : :
169 : 0 : return ret;
170 : : }
171 : :
172 : : /**
173 : : * drm_mode_config_reset - call ->reset callbacks
174 : : * @dev: drm device
175 : : *
176 : : * This functions calls all the crtc's, encoder's and connector's ->reset
177 : : * callback. Drivers can use this in e.g. their driver load or resume code to
178 : : * reset hardware and software state.
179 : : */
180 : 0 : void drm_mode_config_reset(struct drm_device *dev)
181 : : {
182 : 0 : struct drm_crtc *crtc;
183 : 0 : struct drm_plane *plane;
184 : 0 : struct drm_encoder *encoder;
185 : 0 : struct drm_connector *connector;
186 : 0 : struct drm_connector_list_iter conn_iter;
187 : :
188 [ # # ]: 0 : drm_for_each_plane(plane, dev)
189 [ # # ]: 0 : if (plane->funcs->reset)
190 : 0 : plane->funcs->reset(plane);
191 : :
192 [ # # ]: 0 : drm_for_each_crtc(crtc, dev)
193 [ # # ]: 0 : if (crtc->funcs->reset)
194 : 0 : crtc->funcs->reset(crtc);
195 : :
196 [ # # ]: 0 : drm_for_each_encoder(encoder, dev)
197 [ # # ]: 0 : if (encoder->funcs->reset)
198 : 0 : encoder->funcs->reset(encoder);
199 : :
200 : 0 : drm_connector_list_iter_begin(dev, &conn_iter);
201 [ # # ]: 0 : drm_for_each_connector_iter(connector, &conn_iter)
202 [ # # ]: 0 : if (connector->funcs->reset)
203 : 0 : connector->funcs->reset(connector);
204 : 0 : drm_connector_list_iter_end(&conn_iter);
205 : 0 : }
206 : : EXPORT_SYMBOL(drm_mode_config_reset);
207 : :
208 : : /*
209 : : * Global properties
210 : : */
211 : : static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
212 : : { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
213 : : { DRM_PLANE_TYPE_PRIMARY, "Primary" },
214 : : { DRM_PLANE_TYPE_CURSOR, "Cursor" },
215 : : };
216 : :
217 : 0 : static int drm_mode_create_standard_properties(struct drm_device *dev)
218 : : {
219 : 0 : struct drm_property *prop;
220 : 0 : int ret;
221 : :
222 : 0 : ret = drm_connector_create_standard_properties(dev);
223 [ # # ]: 0 : if (ret)
224 : : return ret;
225 : :
226 : 0 : prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
227 : : "type", drm_plane_type_enum_list,
228 : : ARRAY_SIZE(drm_plane_type_enum_list));
229 [ # # ]: 0 : if (!prop)
230 : : return -ENOMEM;
231 : 0 : dev->mode_config.plane_type_property = prop;
232 : :
233 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
234 : : "SRC_X", 0, UINT_MAX);
235 [ # # ]: 0 : if (!prop)
236 : : return -ENOMEM;
237 : 0 : dev->mode_config.prop_src_x = prop;
238 : :
239 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
240 : : "SRC_Y", 0, UINT_MAX);
241 [ # # ]: 0 : if (!prop)
242 : : return -ENOMEM;
243 : 0 : dev->mode_config.prop_src_y = prop;
244 : :
245 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
246 : : "SRC_W", 0, UINT_MAX);
247 [ # # ]: 0 : if (!prop)
248 : : return -ENOMEM;
249 : 0 : dev->mode_config.prop_src_w = prop;
250 : :
251 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
252 : : "SRC_H", 0, UINT_MAX);
253 [ # # ]: 0 : if (!prop)
254 : : return -ENOMEM;
255 : 0 : dev->mode_config.prop_src_h = prop;
256 : :
257 : 0 : prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
258 : : "CRTC_X", INT_MIN, INT_MAX);
259 [ # # ]: 0 : if (!prop)
260 : : return -ENOMEM;
261 : 0 : dev->mode_config.prop_crtc_x = prop;
262 : :
263 : 0 : prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
264 : : "CRTC_Y", INT_MIN, INT_MAX);
265 [ # # ]: 0 : if (!prop)
266 : : return -ENOMEM;
267 : 0 : dev->mode_config.prop_crtc_y = prop;
268 : :
269 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
270 : : "CRTC_W", 0, INT_MAX);
271 [ # # ]: 0 : if (!prop)
272 : : return -ENOMEM;
273 : 0 : dev->mode_config.prop_crtc_w = prop;
274 : :
275 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
276 : : "CRTC_H", 0, INT_MAX);
277 [ # # ]: 0 : if (!prop)
278 : : return -ENOMEM;
279 : 0 : dev->mode_config.prop_crtc_h = prop;
280 : :
281 : 0 : prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
282 : : "FB_ID", DRM_MODE_OBJECT_FB);
283 [ # # ]: 0 : if (!prop)
284 : : return -ENOMEM;
285 : 0 : dev->mode_config.prop_fb_id = prop;
286 : :
287 : 0 : prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
288 : : "IN_FENCE_FD", -1, INT_MAX);
289 [ # # ]: 0 : if (!prop)
290 : : return -ENOMEM;
291 : 0 : dev->mode_config.prop_in_fence_fd = prop;
292 : :
293 : 0 : prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
294 : : "OUT_FENCE_PTR", 0, U64_MAX);
295 [ # # ]: 0 : if (!prop)
296 : : return -ENOMEM;
297 : 0 : dev->mode_config.prop_out_fence_ptr = prop;
298 : :
299 : 0 : prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
300 : : "CRTC_ID", DRM_MODE_OBJECT_CRTC);
301 [ # # ]: 0 : if (!prop)
302 : : return -ENOMEM;
303 : 0 : dev->mode_config.prop_crtc_id = prop;
304 : :
305 : 0 : prop = drm_property_create(dev,
306 : : DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
307 : : "FB_DAMAGE_CLIPS", 0);
308 [ # # ]: 0 : if (!prop)
309 : : return -ENOMEM;
310 : 0 : dev->mode_config.prop_fb_damage_clips = prop;
311 : :
312 : 0 : prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
313 : : "ACTIVE");
314 [ # # ]: 0 : if (!prop)
315 : : return -ENOMEM;
316 : 0 : dev->mode_config.prop_active = prop;
317 : :
318 : 0 : prop = drm_property_create(dev,
319 : : DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
320 : : "MODE_ID", 0);
321 [ # # ]: 0 : if (!prop)
322 : : return -ENOMEM;
323 : 0 : dev->mode_config.prop_mode_id = prop;
324 : :
325 : 0 : prop = drm_property_create_bool(dev, 0,
326 : : "VRR_ENABLED");
327 [ # # ]: 0 : if (!prop)
328 : : return -ENOMEM;
329 : 0 : dev->mode_config.prop_vrr_enabled = prop;
330 : :
331 : 0 : prop = drm_property_create(dev,
332 : : DRM_MODE_PROP_BLOB,
333 : : "DEGAMMA_LUT", 0);
334 [ # # ]: 0 : if (!prop)
335 : : return -ENOMEM;
336 : 0 : dev->mode_config.degamma_lut_property = prop;
337 : :
338 : 0 : prop = drm_property_create_range(dev,
339 : : DRM_MODE_PROP_IMMUTABLE,
340 : : "DEGAMMA_LUT_SIZE", 0, UINT_MAX);
341 [ # # ]: 0 : if (!prop)
342 : : return -ENOMEM;
343 : 0 : dev->mode_config.degamma_lut_size_property = prop;
344 : :
345 : 0 : prop = drm_property_create(dev,
346 : : DRM_MODE_PROP_BLOB,
347 : : "CTM", 0);
348 [ # # ]: 0 : if (!prop)
349 : : return -ENOMEM;
350 : 0 : dev->mode_config.ctm_property = prop;
351 : :
352 : 0 : prop = drm_property_create(dev,
353 : : DRM_MODE_PROP_BLOB,
354 : : "GAMMA_LUT", 0);
355 [ # # ]: 0 : if (!prop)
356 : : return -ENOMEM;
357 : 0 : dev->mode_config.gamma_lut_property = prop;
358 : :
359 : 0 : prop = drm_property_create_range(dev,
360 : : DRM_MODE_PROP_IMMUTABLE,
361 : : "GAMMA_LUT_SIZE", 0, UINT_MAX);
362 [ # # ]: 0 : if (!prop)
363 : : return -ENOMEM;
364 : 0 : dev->mode_config.gamma_lut_size_property = prop;
365 : :
366 : 0 : prop = drm_property_create(dev,
367 : : DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
368 : : "IN_FORMATS", 0);
369 [ # # ]: 0 : if (!prop)
370 : : return -ENOMEM;
371 : 0 : dev->mode_config.modifiers_property = prop;
372 : :
373 : 0 : return 0;
374 : : }
375 : :
376 : : /**
377 : : * drm_mode_config_init - initialize DRM mode_configuration structure
378 : : * @dev: DRM device
379 : : *
380 : : * Initialize @dev's mode_config structure, used for tracking the graphics
381 : : * configuration of @dev.
382 : : *
383 : : * Since this initializes the modeset locks, no locking is possible. Which is no
384 : : * problem, since this should happen single threaded at init time. It is the
385 : : * driver's problem to ensure this guarantee.
386 : : *
387 : : */
388 : 0 : void drm_mode_config_init(struct drm_device *dev)
389 : : {
390 : 0 : mutex_init(&dev->mode_config.mutex);
391 : 0 : drm_modeset_lock_init(&dev->mode_config.connection_mutex);
392 : 0 : mutex_init(&dev->mode_config.idr_mutex);
393 : 0 : mutex_init(&dev->mode_config.fb_lock);
394 : 0 : mutex_init(&dev->mode_config.blob_lock);
395 : 0 : INIT_LIST_HEAD(&dev->mode_config.fb_list);
396 : 0 : INIT_LIST_HEAD(&dev->mode_config.crtc_list);
397 : 0 : INIT_LIST_HEAD(&dev->mode_config.connector_list);
398 : 0 : INIT_LIST_HEAD(&dev->mode_config.encoder_list);
399 : 0 : INIT_LIST_HEAD(&dev->mode_config.property_list);
400 : 0 : INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
401 : 0 : INIT_LIST_HEAD(&dev->mode_config.plane_list);
402 : 0 : INIT_LIST_HEAD(&dev->mode_config.privobj_list);
403 : 0 : idr_init(&dev->mode_config.object_idr);
404 : 0 : idr_init(&dev->mode_config.tile_idr);
405 : 0 : ida_init(&dev->mode_config.connector_ida);
406 : 0 : spin_lock_init(&dev->mode_config.connector_list_lock);
407 : :
408 : 0 : init_llist_head(&dev->mode_config.connector_free_list);
409 : 0 : INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
410 : :
411 : 0 : drm_mode_create_standard_properties(dev);
412 : :
413 : : /* Just to be sure */
414 : 0 : dev->mode_config.num_fb = 0;
415 : 0 : dev->mode_config.num_connector = 0;
416 : 0 : dev->mode_config.num_crtc = 0;
417 : 0 : dev->mode_config.num_encoder = 0;
418 : 0 : dev->mode_config.num_total_plane = 0;
419 : :
420 : 0 : if (IS_ENABLED(CONFIG_LOCKDEP)) {
421 : : struct drm_modeset_acquire_ctx modeset_ctx;
422 : : struct ww_acquire_ctx resv_ctx;
423 : : struct dma_resv resv;
424 : : int ret;
425 : :
426 : : dma_resv_init(&resv);
427 : :
428 : : drm_modeset_acquire_init(&modeset_ctx, 0);
429 : : ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
430 : : &modeset_ctx);
431 : : if (ret == -EDEADLK)
432 : : ret = drm_modeset_backoff(&modeset_ctx);
433 : :
434 : : ww_acquire_init(&resv_ctx, &reservation_ww_class);
435 : : ret = dma_resv_lock(&resv, &resv_ctx);
436 : : if (ret == -EDEADLK)
437 : : dma_resv_lock_slow(&resv, &resv_ctx);
438 : :
439 : : dma_resv_unlock(&resv);
440 : : ww_acquire_fini(&resv_ctx);
441 : :
442 : : drm_modeset_drop_locks(&modeset_ctx);
443 : : drm_modeset_acquire_fini(&modeset_ctx);
444 : : dma_resv_fini(&resv);
445 : : }
446 : 0 : }
447 : : EXPORT_SYMBOL(drm_mode_config_init);
448 : :
449 : : /**
450 : : * drm_mode_config_cleanup - free up DRM mode_config info
451 : : * @dev: DRM device
452 : : *
453 : : * Free up all the connectors and CRTCs associated with this DRM device, then
454 : : * free up the framebuffers and associated buffer objects.
455 : : *
456 : : * Note that since this /should/ happen single-threaded at driver/device
457 : : * teardown time, no locking is required. It's the driver's job to ensure that
458 : : * this guarantee actually holds true.
459 : : */
460 : 0 : void drm_mode_config_cleanup(struct drm_device *dev)
461 : : {
462 : 0 : struct drm_connector *connector;
463 : 0 : struct drm_connector_list_iter conn_iter;
464 : 0 : struct drm_crtc *crtc, *ct;
465 : 0 : struct drm_encoder *encoder, *enct;
466 : 0 : struct drm_framebuffer *fb, *fbt;
467 : 0 : struct drm_property *property, *pt;
468 : 0 : struct drm_property_blob *blob, *bt;
469 : 0 : struct drm_plane *plane, *plt;
470 : :
471 [ # # ]: 0 : list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
472 : : head) {
473 : 0 : encoder->funcs->destroy(encoder);
474 : : }
475 : :
476 : 0 : drm_connector_list_iter_begin(dev, &conn_iter);
477 [ # # ]: 0 : drm_for_each_connector_iter(connector, &conn_iter) {
478 : : /* drm_connector_list_iter holds an full reference to the
479 : : * current connector itself, which means it is inherently safe
480 : : * against unreferencing the current connector - but not against
481 : : * deleting it right away. */
482 : 0 : drm_connector_put(connector);
483 : : }
484 : 0 : drm_connector_list_iter_end(&conn_iter);
485 : : /* connector_iter drops references in a work item. */
486 : 0 : flush_work(&dev->mode_config.connector_free_work);
487 [ # # # # ]: 0 : if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
488 : 0 : drm_connector_list_iter_begin(dev, &conn_iter);
489 [ # # ]: 0 : drm_for_each_connector_iter(connector, &conn_iter)
490 : 0 : DRM_ERROR("connector %s leaked!\n", connector->name);
491 : 0 : drm_connector_list_iter_end(&conn_iter);
492 : : }
493 : :
494 [ # # ]: 0 : list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
495 : : head) {
496 : 0 : drm_property_destroy(dev, property);
497 : : }
498 : :
499 [ # # ]: 0 : list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
500 : : head) {
501 : 0 : plane->funcs->destroy(plane);
502 : : }
503 : :
504 [ # # ]: 0 : list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
505 : 0 : crtc->funcs->destroy(crtc);
506 : : }
507 : :
508 [ # # ]: 0 : list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
509 : : head_global) {
510 : 0 : drm_property_blob_put(blob);
511 : : }
512 : :
513 : : /*
514 : : * Single-threaded teardown context, so it's not required to grab the
515 : : * fb_lock to protect against concurrent fb_list access. Contrary, it
516 : : * would actually deadlock with the drm_framebuffer_cleanup function.
517 : : *
518 : : * Also, if there are any framebuffers left, that's a driver leak now,
519 : : * so politely WARN about this.
520 : : */
521 [ # # ]: 0 : WARN_ON(!list_empty(&dev->mode_config.fb_list));
522 [ # # ]: 0 : list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
523 : 0 : struct drm_printer p = drm_debug_printer("[leaked fb]");
524 : 0 : drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
525 : 0 : drm_framebuffer_print_info(&p, 1, fb);
526 : 0 : drm_framebuffer_free(&fb->base.refcount);
527 : : }
528 : :
529 : 0 : ida_destroy(&dev->mode_config.connector_ida);
530 : 0 : idr_destroy(&dev->mode_config.tile_idr);
531 : 0 : idr_destroy(&dev->mode_config.object_idr);
532 [ # # ]: 0 : drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
533 : 0 : }
534 : : EXPORT_SYMBOL(drm_mode_config_cleanup);
|