LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_mode_config.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 147 265 55.5 %
Date: 2023-04-06 08:38:28 Functions: 7 11 63.6 %

          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_framebuffer.h>
      29             : #include <drm/drm_managed.h>
      30             : #include <drm/drm_mode_config.h>
      31             : #include <drm/drm_print.h>
      32             : #include <linux/dma-resv.h>
      33             : 
      34             : #include "drm_crtc_internal.h"
      35             : #include "drm_internal.h"
      36             : 
      37           1 : int drm_modeset_register_all(struct drm_device *dev)
      38             : {
      39             :         int ret;
      40             : 
      41           1 :         ret = drm_plane_register_all(dev);
      42           1 :         if (ret)
      43             :                 goto err_plane;
      44             : 
      45           1 :         ret = drm_crtc_register_all(dev);
      46           1 :         if  (ret)
      47             :                 goto err_crtc;
      48             : 
      49           1 :         ret = drm_encoder_register_all(dev);
      50           1 :         if (ret)
      51             :                 goto err_encoder;
      52             : 
      53           1 :         ret = drm_connector_register_all(dev);
      54           1 :         if (ret)
      55             :                 goto err_connector;
      56             : 
      57             :         drm_debugfs_late_register(dev);
      58             : 
      59             :         return 0;
      60             : 
      61             : err_connector:
      62           0 :         drm_encoder_unregister_all(dev);
      63             : err_encoder:
      64           0 :         drm_crtc_unregister_all(dev);
      65             : err_crtc:
      66           0 :         drm_plane_unregister_all(dev);
      67             : err_plane:
      68             :         return ret;
      69             : }
      70             : 
      71           1 : void drm_modeset_unregister_all(struct drm_device *dev)
      72             : {
      73           1 :         drm_connector_unregister_all(dev);
      74           1 :         drm_encoder_unregister_all(dev);
      75           1 :         drm_crtc_unregister_all(dev);
      76           1 :         drm_plane_unregister_all(dev);
      77           1 : }
      78             : 
      79             : /**
      80             :  * drm_mode_getresources - get graphics configuration
      81             :  * @dev: drm device for the ioctl
      82             :  * @data: data pointer for the ioctl
      83             :  * @file_priv: drm file for the ioctl call
      84             :  *
      85             :  * Construct a set of configuration description structures and return
      86             :  * them to the user, including CRTC, connector and framebuffer configuration.
      87             :  *
      88             :  * Called by the user via ioctl.
      89             :  *
      90             :  * Returns:
      91             :  * Zero on success, negative errno on failure.
      92             :  */
      93           0 : int drm_mode_getresources(struct drm_device *dev, void *data,
      94             :                           struct drm_file *file_priv)
      95             : {
      96           0 :         struct drm_mode_card_res *card_res = data;
      97             :         struct drm_framebuffer *fb;
      98             :         struct drm_connector *connector;
      99             :         struct drm_crtc *crtc;
     100             :         struct drm_encoder *encoder;
     101           0 :         int count, ret = 0;
     102             :         uint32_t __user *fb_id;
     103             :         uint32_t __user *crtc_id;
     104             :         uint32_t __user *connector_id;
     105             :         uint32_t __user *encoder_id;
     106             :         struct drm_connector_list_iter conn_iter;
     107             : 
     108           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     109             :                 return -EOPNOTSUPP;
     110             : 
     111           0 :         mutex_lock(&file_priv->fbs_lock);
     112           0 :         count = 0;
     113           0 :         fb_id = u64_to_user_ptr(card_res->fb_id_ptr);
     114           0 :         list_for_each_entry(fb, &file_priv->fbs, filp_head) {
     115           0 :                 if (count < card_res->count_fbs &&
     116           0 :                     put_user(fb->base.id, fb_id + count)) {
     117           0 :                         mutex_unlock(&file_priv->fbs_lock);
     118           0 :                         return -EFAULT;
     119             :                 }
     120           0 :                 count++;
     121             :         }
     122           0 :         card_res->count_fbs = count;
     123           0 :         mutex_unlock(&file_priv->fbs_lock);
     124             : 
     125           0 :         card_res->max_height = dev->mode_config.max_height;
     126           0 :         card_res->min_height = dev->mode_config.min_height;
     127           0 :         card_res->max_width = dev->mode_config.max_width;
     128           0 :         card_res->min_width = dev->mode_config.min_width;
     129             : 
     130           0 :         count = 0;
     131           0 :         crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
     132           0 :         drm_for_each_crtc(crtc, dev) {
     133           0 :                 if (drm_lease_held(file_priv, crtc->base.id)) {
     134           0 :                         if (count < card_res->count_crtcs &&
     135           0 :                             put_user(crtc->base.id, crtc_id + count))
     136             :                                 return -EFAULT;
     137           0 :                         count++;
     138             :                 }
     139             :         }
     140           0 :         card_res->count_crtcs = count;
     141             : 
     142           0 :         count = 0;
     143           0 :         encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
     144           0 :         drm_for_each_encoder(encoder, dev) {
     145           0 :                 if (count < card_res->count_encoders &&
     146           0 :                     put_user(encoder->base.id, encoder_id + count))
     147             :                         return -EFAULT;
     148           0 :                 count++;
     149             :         }
     150           0 :         card_res->count_encoders = count;
     151             : 
     152           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     153           0 :         count = 0;
     154           0 :         connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
     155           0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     156             :                 /* only expose writeback connectors if userspace understands them */
     157           0 :                 if (!file_priv->writeback_connectors &&
     158           0 :                     (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
     159           0 :                         continue;
     160             : 
     161           0 :                 if (drm_lease_held(file_priv, connector->base.id)) {
     162           0 :                         if (count < card_res->count_connectors &&
     163           0 :                             put_user(connector->base.id, connector_id + count)) {
     164           0 :                                 drm_connector_list_iter_end(&conn_iter);
     165           0 :                                 return -EFAULT;
     166             :                         }
     167           0 :                         count++;
     168             :                 }
     169             :         }
     170           0 :         card_res->count_connectors = count;
     171           0 :         drm_connector_list_iter_end(&conn_iter);
     172             : 
     173           0 :         return ret;
     174             : }
     175             : 
     176             : /**
     177             :  * drm_mode_config_reset - call ->reset callbacks
     178             :  * @dev: drm device
     179             :  *
     180             :  * This functions calls all the crtc's, encoder's and connector's ->reset
     181             :  * callback. Drivers can use this in e.g. their driver load or resume code to
     182             :  * reset hardware and software state.
     183             :  */
     184           0 : void drm_mode_config_reset(struct drm_device *dev)
     185             : {
     186             :         struct drm_crtc *crtc;
     187             :         struct drm_plane *plane;
     188             :         struct drm_encoder *encoder;
     189             :         struct drm_connector *connector;
     190             :         struct drm_connector_list_iter conn_iter;
     191             : 
     192           0 :         drm_for_each_plane(plane, dev)
     193           0 :                 if (plane->funcs->reset)
     194           0 :                         plane->funcs->reset(plane);
     195             : 
     196           0 :         drm_for_each_crtc(crtc, dev)
     197           0 :                 if (crtc->funcs->reset)
     198           0 :                         crtc->funcs->reset(crtc);
     199             : 
     200           0 :         drm_for_each_encoder(encoder, dev)
     201           0 :                 if (encoder->funcs && encoder->funcs->reset)
     202           0 :                         encoder->funcs->reset(encoder);
     203             : 
     204           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     205           0 :         drm_for_each_connector_iter(connector, &conn_iter)
     206           0 :                 if (connector->funcs->reset)
     207           0 :                         connector->funcs->reset(connector);
     208           0 :         drm_connector_list_iter_end(&conn_iter);
     209           0 : }
     210             : EXPORT_SYMBOL(drm_mode_config_reset);
     211             : 
     212             : /*
     213             :  * Global properties
     214             :  */
     215             : static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
     216             :         { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
     217             :         { DRM_PLANE_TYPE_PRIMARY, "Primary" },
     218             :         { DRM_PLANE_TYPE_CURSOR, "Cursor" },
     219             : };
     220             : 
     221          17 : static int drm_mode_create_standard_properties(struct drm_device *dev)
     222             : {
     223             :         struct drm_property *prop;
     224             :         int ret;
     225             : 
     226          17 :         ret = drm_connector_create_standard_properties(dev);
     227          17 :         if (ret)
     228             :                 return ret;
     229             : 
     230          17 :         prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
     231             :                                         "type", drm_plane_type_enum_list,
     232             :                                         ARRAY_SIZE(drm_plane_type_enum_list));
     233          17 :         if (!prop)
     234             :                 return -ENOMEM;
     235          17 :         dev->mode_config.plane_type_property = prop;
     236             : 
     237          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     238             :                         "SRC_X", 0, UINT_MAX);
     239          17 :         if (!prop)
     240             :                 return -ENOMEM;
     241          17 :         dev->mode_config.prop_src_x = prop;
     242             : 
     243          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     244             :                         "SRC_Y", 0, UINT_MAX);
     245          17 :         if (!prop)
     246             :                 return -ENOMEM;
     247          17 :         dev->mode_config.prop_src_y = prop;
     248             : 
     249          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     250             :                         "SRC_W", 0, UINT_MAX);
     251          17 :         if (!prop)
     252             :                 return -ENOMEM;
     253          17 :         dev->mode_config.prop_src_w = prop;
     254             : 
     255          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     256             :                         "SRC_H", 0, UINT_MAX);
     257          17 :         if (!prop)
     258             :                 return -ENOMEM;
     259          17 :         dev->mode_config.prop_src_h = prop;
     260             : 
     261          17 :         prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
     262             :                         "CRTC_X", INT_MIN, INT_MAX);
     263          17 :         if (!prop)
     264             :                 return -ENOMEM;
     265          17 :         dev->mode_config.prop_crtc_x = prop;
     266             : 
     267          17 :         prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
     268             :                         "CRTC_Y", INT_MIN, INT_MAX);
     269          17 :         if (!prop)
     270             :                 return -ENOMEM;
     271          17 :         dev->mode_config.prop_crtc_y = prop;
     272             : 
     273          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     274             :                         "CRTC_W", 0, INT_MAX);
     275          17 :         if (!prop)
     276             :                 return -ENOMEM;
     277          17 :         dev->mode_config.prop_crtc_w = prop;
     278             : 
     279          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     280             :                         "CRTC_H", 0, INT_MAX);
     281          17 :         if (!prop)
     282             :                 return -ENOMEM;
     283          17 :         dev->mode_config.prop_crtc_h = prop;
     284             : 
     285          17 :         prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
     286             :                         "FB_ID", DRM_MODE_OBJECT_FB);
     287          17 :         if (!prop)
     288             :                 return -ENOMEM;
     289          17 :         dev->mode_config.prop_fb_id = prop;
     290             : 
     291          17 :         prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
     292             :                         "IN_FENCE_FD", -1, INT_MAX);
     293          17 :         if (!prop)
     294             :                 return -ENOMEM;
     295          17 :         dev->mode_config.prop_in_fence_fd = prop;
     296             : 
     297          17 :         prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
     298             :                         "OUT_FENCE_PTR", 0, U64_MAX);
     299          17 :         if (!prop)
     300             :                 return -ENOMEM;
     301          17 :         dev->mode_config.prop_out_fence_ptr = prop;
     302             : 
     303          17 :         prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
     304             :                         "CRTC_ID", DRM_MODE_OBJECT_CRTC);
     305          17 :         if (!prop)
     306             :                 return -ENOMEM;
     307          17 :         dev->mode_config.prop_crtc_id = prop;
     308             : 
     309          17 :         prop = drm_property_create(dev,
     310             :                         DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
     311             :                         "FB_DAMAGE_CLIPS", 0);
     312          17 :         if (!prop)
     313             :                 return -ENOMEM;
     314          17 :         dev->mode_config.prop_fb_damage_clips = prop;
     315             : 
     316          17 :         prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
     317             :                         "ACTIVE");
     318          17 :         if (!prop)
     319             :                 return -ENOMEM;
     320          17 :         dev->mode_config.prop_active = prop;
     321             : 
     322          17 :         prop = drm_property_create(dev,
     323             :                         DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
     324             :                         "MODE_ID", 0);
     325          17 :         if (!prop)
     326             :                 return -ENOMEM;
     327          17 :         dev->mode_config.prop_mode_id = prop;
     328             : 
     329          17 :         prop = drm_property_create_bool(dev, 0,
     330             :                         "VRR_ENABLED");
     331          17 :         if (!prop)
     332             :                 return -ENOMEM;
     333          17 :         dev->mode_config.prop_vrr_enabled = prop;
     334             : 
     335          17 :         prop = drm_property_create(dev,
     336             :                         DRM_MODE_PROP_BLOB,
     337             :                         "DEGAMMA_LUT", 0);
     338          17 :         if (!prop)
     339             :                 return -ENOMEM;
     340          17 :         dev->mode_config.degamma_lut_property = prop;
     341             : 
     342          17 :         prop = drm_property_create_range(dev,
     343             :                         DRM_MODE_PROP_IMMUTABLE,
     344             :                         "DEGAMMA_LUT_SIZE", 0, UINT_MAX);
     345          17 :         if (!prop)
     346             :                 return -ENOMEM;
     347          17 :         dev->mode_config.degamma_lut_size_property = prop;
     348             : 
     349          17 :         prop = drm_property_create(dev,
     350             :                         DRM_MODE_PROP_BLOB,
     351             :                         "CTM", 0);
     352          17 :         if (!prop)
     353             :                 return -ENOMEM;
     354          17 :         dev->mode_config.ctm_property = prop;
     355             : 
     356          17 :         prop = drm_property_create(dev,
     357             :                         DRM_MODE_PROP_BLOB,
     358             :                         "GAMMA_LUT", 0);
     359          17 :         if (!prop)
     360             :                 return -ENOMEM;
     361          17 :         dev->mode_config.gamma_lut_property = prop;
     362             : 
     363          17 :         prop = drm_property_create_range(dev,
     364             :                         DRM_MODE_PROP_IMMUTABLE,
     365             :                         "GAMMA_LUT_SIZE", 0, UINT_MAX);
     366          17 :         if (!prop)
     367             :                 return -ENOMEM;
     368          17 :         dev->mode_config.gamma_lut_size_property = prop;
     369             : 
     370          17 :         prop = drm_property_create(dev,
     371             :                                    DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
     372             :                                    "IN_FORMATS", 0);
     373          17 :         if (!prop)
     374             :                 return -ENOMEM;
     375          17 :         dev->mode_config.modifiers_property = prop;
     376             : 
     377          17 :         return 0;
     378             : }
     379             : 
     380          17 : static void drm_mode_config_init_release(struct drm_device *dev, void *ptr)
     381             : {
     382          17 :         drm_mode_config_cleanup(dev);
     383          17 : }
     384             : 
     385             : /**
     386             :  * drmm_mode_config_init - managed DRM mode_configuration structure
     387             :  *      initialization
     388             :  * @dev: DRM device
     389             :  *
     390             :  * Initialize @dev's mode_config structure, used for tracking the graphics
     391             :  * configuration of @dev.
     392             :  *
     393             :  * Since this initializes the modeset locks, no locking is possible. Which is no
     394             :  * problem, since this should happen single threaded at init time. It is the
     395             :  * driver's problem to ensure this guarantee.
     396             :  *
     397             :  * Cleanup is automatically handled through registering drm_mode_config_cleanup
     398             :  * with drmm_add_action().
     399             :  *
     400             :  * Returns: 0 on success, negative error value on failure.
     401             :  */
     402          17 : int drmm_mode_config_init(struct drm_device *dev)
     403             : {
     404             :         int ret;
     405             : 
     406          17 :         mutex_init(&dev->mode_config.mutex);
     407          17 :         drm_modeset_lock_init(&dev->mode_config.connection_mutex);
     408          17 :         mutex_init(&dev->mode_config.idr_mutex);
     409          17 :         mutex_init(&dev->mode_config.fb_lock);
     410          17 :         mutex_init(&dev->mode_config.blob_lock);
     411          34 :         INIT_LIST_HEAD(&dev->mode_config.fb_list);
     412          34 :         INIT_LIST_HEAD(&dev->mode_config.crtc_list);
     413          34 :         INIT_LIST_HEAD(&dev->mode_config.connector_list);
     414          34 :         INIT_LIST_HEAD(&dev->mode_config.encoder_list);
     415          34 :         INIT_LIST_HEAD(&dev->mode_config.property_list);
     416          34 :         INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
     417          34 :         INIT_LIST_HEAD(&dev->mode_config.plane_list);
     418          34 :         INIT_LIST_HEAD(&dev->mode_config.privobj_list);
     419          34 :         idr_init_base(&dev->mode_config.object_idr, 1);
     420          34 :         idr_init_base(&dev->mode_config.tile_idr, 1);
     421          34 :         ida_init(&dev->mode_config.connector_ida);
     422          17 :         spin_lock_init(&dev->mode_config.connector_list_lock);
     423             : 
     424          34 :         init_llist_head(&dev->mode_config.connector_free_list);
     425          34 :         INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
     426             : 
     427          17 :         ret = drm_mode_create_standard_properties(dev);
     428          17 :         if (ret) {
     429           0 :                 drm_mode_config_cleanup(dev);
     430           0 :                 return ret;
     431             :         }
     432             : 
     433             :         /* Just to be sure */
     434          17 :         dev->mode_config.num_fb = 0;
     435          17 :         dev->mode_config.num_connector = 0;
     436          17 :         dev->mode_config.num_crtc = 0;
     437          17 :         dev->mode_config.num_encoder = 0;
     438          17 :         dev->mode_config.num_total_plane = 0;
     439             : 
     440             :         if (IS_ENABLED(CONFIG_LOCKDEP)) {
     441             :                 struct drm_modeset_acquire_ctx modeset_ctx;
     442             :                 struct ww_acquire_ctx resv_ctx;
     443             :                 struct dma_resv resv;
     444             :                 int ret;
     445             : 
     446             :                 dma_resv_init(&resv);
     447             : 
     448             :                 drm_modeset_acquire_init(&modeset_ctx, 0);
     449             :                 ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
     450             :                                        &modeset_ctx);
     451             :                 if (ret == -EDEADLK)
     452             :                         ret = drm_modeset_backoff(&modeset_ctx);
     453             : 
     454             :                 ww_acquire_init(&resv_ctx, &reservation_ww_class);
     455             :                 ret = dma_resv_lock(&resv, &resv_ctx);
     456             :                 if (ret == -EDEADLK)
     457             :                         dma_resv_lock_slow(&resv, &resv_ctx);
     458             : 
     459             :                 dma_resv_unlock(&resv);
     460             :                 ww_acquire_fini(&resv_ctx);
     461             : 
     462             :                 drm_modeset_drop_locks(&modeset_ctx);
     463             :                 drm_modeset_acquire_fini(&modeset_ctx);
     464             :                 dma_resv_fini(&resv);
     465             :         }
     466             : 
     467          17 :         return drmm_add_action_or_reset(dev, drm_mode_config_init_release,
     468             :                                         NULL);
     469             : }
     470             : EXPORT_SYMBOL(drmm_mode_config_init);
     471             : 
     472             : /**
     473             :  * drm_mode_config_cleanup - free up DRM mode_config info
     474             :  * @dev: DRM device
     475             :  *
     476             :  * Free up all the connectors and CRTCs associated with this DRM device, then
     477             :  * free up the framebuffers and associated buffer objects.
     478             :  *
     479             :  * Note that since this /should/ happen single-threaded at driver/device
     480             :  * teardown time, no locking is required. It's the driver's job to ensure that
     481             :  * this guarantee actually holds true.
     482             :  *
     483             :  * FIXME: With the managed drmm_mode_config_init() it is no longer necessary for
     484             :  * drivers to explicitly call this function.
     485             :  */
     486          17 : void drm_mode_config_cleanup(struct drm_device *dev)
     487             : {
     488             :         struct drm_connector *connector;
     489             :         struct drm_connector_list_iter conn_iter;
     490             :         struct drm_crtc *crtc, *ct;
     491             :         struct drm_encoder *encoder, *enct;
     492             :         struct drm_framebuffer *fb, *fbt;
     493             :         struct drm_property *property, *pt;
     494             :         struct drm_property_blob *blob, *bt;
     495             :         struct drm_plane *plane, *plt;
     496             : 
     497          17 :         list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
     498             :                                  head) {
     499           0 :                 encoder->funcs->destroy(encoder);
     500             :         }
     501             : 
     502          17 :         drm_connector_list_iter_begin(dev, &conn_iter);
     503          34 :         drm_for_each_connector_iter(connector, &conn_iter) {
     504             :                 /* drm_connector_list_iter holds an full reference to the
     505             :                  * current connector itself, which means it is inherently safe
     506             :                  * against unreferencing the current connector - but not against
     507             :                  * deleting it right away. */
     508             :                 drm_connector_put(connector);
     509             :         }
     510          17 :         drm_connector_list_iter_end(&conn_iter);
     511             :         /* connector_iter drops references in a work item. */
     512          17 :         flush_work(&dev->mode_config.connector_free_work);
     513          34 :         if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
     514           0 :                 drm_connector_list_iter_begin(dev, &conn_iter);
     515           0 :                 drm_for_each_connector_iter(connector, &conn_iter)
     516           0 :                         DRM_ERROR("connector %s leaked!\n", connector->name);
     517           0 :                 drm_connector_list_iter_end(&conn_iter);
     518             :         }
     519             : 
     520         618 :         list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
     521             :                                  head) {
     522         601 :                 drm_property_destroy(dev, property);
     523             :         }
     524             : 
     525          17 :         list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
     526             :                                  head) {
     527           0 :                 plane->funcs->destroy(plane);
     528             :         }
     529             : 
     530          17 :         list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
     531           0 :                 crtc->funcs->destroy(crtc);
     532             :         }
     533             : 
     534          17 :         list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
     535             :                                  head_global) {
     536           0 :                 drm_property_blob_put(blob);
     537             :         }
     538             : 
     539             :         /*
     540             :          * Single-threaded teardown context, so it's not required to grab the
     541             :          * fb_lock to protect against concurrent fb_list access. Contrary, it
     542             :          * would actually deadlock with the drm_framebuffer_cleanup function.
     543             :          *
     544             :          * Also, if there are any framebuffers left, that's a driver leak now,
     545             :          * so politely WARN about this.
     546             :          */
     547          34 :         WARN_ON(!list_empty(&dev->mode_config.fb_list));
     548          17 :         list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
     549           0 :                 struct drm_printer p = drm_debug_printer("[leaked fb]");
     550             : 
     551           0 :                 drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
     552           0 :                 drm_framebuffer_print_info(&p, 1, fb);
     553           0 :                 drm_framebuffer_free(&fb->base.refcount);
     554             :         }
     555             : 
     556          17 :         ida_destroy(&dev->mode_config.connector_ida);
     557          17 :         idr_destroy(&dev->mode_config.tile_idr);
     558          17 :         idr_destroy(&dev->mode_config.object_idr);
     559          34 :         drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
     560          17 : }
     561             : EXPORT_SYMBOL(drm_mode_config_cleanup);
     562             : 
     563             : static u32 full_encoder_mask(struct drm_device *dev)
     564             : {
     565             :         struct drm_encoder *encoder;
     566           0 :         u32 encoder_mask = 0;
     567             : 
     568           0 :         drm_for_each_encoder(encoder, dev)
     569           0 :                 encoder_mask |= drm_encoder_mask(encoder);
     570             : 
     571             :         return encoder_mask;
     572             : }
     573             : 
     574             : /*
     575             :  * For some reason we want the encoder itself included in
     576             :  * possible_clones. Make life easy for drivers by allowing them
     577             :  * to leave possible_clones unset if no cloning is possible.
     578             :  */
     579             : static void fixup_encoder_possible_clones(struct drm_encoder *encoder)
     580             : {
     581           0 :         if (encoder->possible_clones == 0)
     582           0 :                 encoder->possible_clones = drm_encoder_mask(encoder);
     583             : }
     584             : 
     585           0 : static void validate_encoder_possible_clones(struct drm_encoder *encoder)
     586             : {
     587           0 :         struct drm_device *dev = encoder->dev;
     588             :         u32 encoder_mask = full_encoder_mask(dev);
     589             :         struct drm_encoder *other;
     590             : 
     591           0 :         drm_for_each_encoder(other, dev) {
     592           0 :                 WARN(!!(encoder->possible_clones & drm_encoder_mask(other)) !=
     593             :                      !!(other->possible_clones & drm_encoder_mask(encoder)),
     594             :                      "possible_clones mismatch: "
     595             :                      "[ENCODER:%d:%s] mask=0x%x possible_clones=0x%x vs. "
     596             :                      "[ENCODER:%d:%s] mask=0x%x possible_clones=0x%x\n",
     597             :                      encoder->base.id, encoder->name,
     598             :                      drm_encoder_mask(encoder), encoder->possible_clones,
     599             :                      other->base.id, other->name,
     600             :                      drm_encoder_mask(other), other->possible_clones);
     601             :         }
     602             : 
     603           0 :         WARN((encoder->possible_clones & drm_encoder_mask(encoder)) == 0 ||
     604             :              (encoder->possible_clones & ~encoder_mask) != 0,
     605             :              "Bogus possible_clones: "
     606             :              "[ENCODER:%d:%s] possible_clones=0x%x (full encoder mask=0x%x)\n",
     607             :              encoder->base.id, encoder->name,
     608             :              encoder->possible_clones, encoder_mask);
     609           0 : }
     610             : 
     611             : static u32 full_crtc_mask(struct drm_device *dev)
     612             : {
     613             :         struct drm_crtc *crtc;
     614           0 :         u32 crtc_mask = 0;
     615             : 
     616           0 :         drm_for_each_crtc(crtc, dev)
     617           0 :                 crtc_mask |= drm_crtc_mask(crtc);
     618             : 
     619             :         return crtc_mask;
     620             : }
     621             : 
     622           0 : static void validate_encoder_possible_crtcs(struct drm_encoder *encoder)
     623             : {
     624           0 :         u32 crtc_mask = full_crtc_mask(encoder->dev);
     625             : 
     626           0 :         WARN((encoder->possible_crtcs & crtc_mask) == 0 ||
     627             :              (encoder->possible_crtcs & ~crtc_mask) != 0,
     628             :              "Bogus possible_crtcs: "
     629             :              "[ENCODER:%d:%s] possible_crtcs=0x%x (full crtc mask=0x%x)\n",
     630             :              encoder->base.id, encoder->name,
     631             :              encoder->possible_crtcs, crtc_mask);
     632           0 : }
     633             : 
     634           1 : void drm_mode_config_validate(struct drm_device *dev)
     635             : {
     636             :         struct drm_encoder *encoder;
     637             :         struct drm_crtc *crtc;
     638             :         struct drm_plane *plane;
     639           1 :         u32 primary_with_crtc = 0, cursor_with_crtc = 0;
     640           1 :         unsigned int num_primary = 0;
     641             : 
     642           1 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     643             :                 return;
     644             : 
     645           1 :         drm_for_each_encoder(encoder, dev)
     646           0 :                 fixup_encoder_possible_clones(encoder);
     647             : 
     648           1 :         drm_for_each_encoder(encoder, dev) {
     649           0 :                 validate_encoder_possible_clones(encoder);
     650           0 :                 validate_encoder_possible_crtcs(encoder);
     651             :         }
     652             : 
     653           1 :         drm_for_each_crtc(crtc, dev) {
     654           0 :                 WARN(!crtc->primary, "Missing primary plane on [CRTC:%d:%s]\n",
     655             :                      crtc->base.id, crtc->name);
     656             : 
     657           0 :                 WARN(crtc->cursor && crtc->funcs->cursor_set,
     658             :                      "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set func",
     659             :                      crtc->base.id, crtc->name);
     660           0 :                 WARN(crtc->cursor && crtc->funcs->cursor_set2,
     661             :                      "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set2 func",
     662             :                      crtc->base.id, crtc->name);
     663           0 :                 WARN(crtc->cursor && crtc->funcs->cursor_move,
     664             :                      "[CRTC:%d:%s] must not have both a cursor plane and a cursor_move func",
     665             :                      crtc->base.id, crtc->name);
     666             : 
     667           0 :                 if (crtc->primary) {
     668           0 :                         WARN(!(crtc->primary->possible_crtcs & drm_crtc_mask(crtc)),
     669             :                              "Bogus primary plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
     670             :                              crtc->primary->base.id, crtc->primary->name,
     671             :                              crtc->base.id, crtc->name);
     672           0 :                         WARN(primary_with_crtc & drm_plane_mask(crtc->primary),
     673             :                              "Primary plane [PLANE:%d:%s] used for multiple CRTCs",
     674             :                              crtc->primary->base.id, crtc->primary->name);
     675           0 :                         primary_with_crtc |= drm_plane_mask(crtc->primary);
     676             :                 }
     677           0 :                 if (crtc->cursor) {
     678           0 :                         WARN(!(crtc->cursor->possible_crtcs & drm_crtc_mask(crtc)),
     679             :                              "Bogus cursor plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
     680             :                              crtc->cursor->base.id, crtc->cursor->name,
     681             :                              crtc->base.id, crtc->name);
     682           0 :                         WARN(cursor_with_crtc & drm_plane_mask(crtc->cursor),
     683             :                              "Cursor plane [PLANE:%d:%s] used for multiple CRTCs",
     684             :                              crtc->cursor->base.id, crtc->cursor->name);
     685           0 :                         cursor_with_crtc |= drm_plane_mask(crtc->cursor);
     686             :                 }
     687             :         }
     688             : 
     689           1 :         drm_for_each_plane(plane, dev) {
     690           0 :                 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
     691           0 :                         num_primary++;
     692             :         }
     693             : 
     694           1 :         WARN(num_primary != dev->mode_config.num_crtc,
     695             :              "Must have as many primary planes as there are CRTCs, but have %u primary planes and %u CRTCs",
     696             :              num_primary, dev->mode_config.num_crtc);
     697             : }

Generated by: LCOV version 1.14