LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_mode_config.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 262 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 11 0.0 %

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

Generated by: LCOV version 1.14