LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_framebuffer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 382 18.1 %
Date: 2023-04-06 08:38:28 Functions: 2 25 8.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/export.h>
      24             : #include <linux/uaccess.h>
      25             : 
      26             : #include <drm/drm_atomic.h>
      27             : #include <drm/drm_atomic_uapi.h>
      28             : #include <drm/drm_auth.h>
      29             : #include <drm/drm_debugfs.h>
      30             : #include <drm/drm_drv.h>
      31             : #include <drm/drm_file.h>
      32             : #include <drm/drm_fourcc.h>
      33             : #include <drm/drm_framebuffer.h>
      34             : #include <drm/drm_gem.h>
      35             : #include <drm/drm_print.h>
      36             : #include <drm/drm_util.h>
      37             : 
      38             : #include "drm_crtc_internal.h"
      39             : #include "drm_internal.h"
      40             : 
      41             : /**
      42             :  * DOC: overview
      43             :  *
      44             :  * Frame buffers are abstract memory objects that provide a source of pixels to
      45             :  * scanout to a CRTC. Applications explicitly request the creation of frame
      46             :  * buffers through the DRM_IOCTL_MODE_ADDFB(2) ioctls and receive an opaque
      47             :  * handle that can be passed to the KMS CRTC control, plane configuration and
      48             :  * page flip functions.
      49             :  *
      50             :  * Frame buffers rely on the underlying memory manager for allocating backing
      51             :  * storage. When creating a frame buffer applications pass a memory handle
      52             :  * (or a list of memory handles for multi-planar formats) through the
      53             :  * &struct drm_mode_fb_cmd2 argument. For drivers using GEM as their userspace
      54             :  * buffer management interface this would be a GEM handle.  Drivers are however
      55             :  * free to use their own backing storage object handles, e.g. vmwgfx directly
      56             :  * exposes special TTM handles to userspace and so expects TTM handles in the
      57             :  * create ioctl and not GEM handles.
      58             :  *
      59             :  * Framebuffers are tracked with &struct drm_framebuffer. They are published
      60             :  * using drm_framebuffer_init() - after calling that function userspace can use
      61             :  * and access the framebuffer object. The helper function
      62             :  * drm_helper_mode_fill_fb_struct() can be used to pre-fill the required
      63             :  * metadata fields.
      64             :  *
      65             :  * The lifetime of a drm framebuffer is controlled with a reference count,
      66             :  * drivers can grab additional references with drm_framebuffer_get() and drop
      67             :  * them again with drm_framebuffer_put(). For driver-private framebuffers for
      68             :  * which the last reference is never dropped (e.g. for the fbdev framebuffer
      69             :  * when the struct &struct drm_framebuffer is embedded into the fbdev helper
      70             :  * struct) drivers can manually clean up a framebuffer at module unload time
      71             :  * with drm_framebuffer_unregister_private(). But doing this is not
      72             :  * recommended, and it's better to have a normal free-standing &struct
      73             :  * drm_framebuffer.
      74             :  */
      75             : 
      76           0 : int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
      77             :                                      uint32_t src_w, uint32_t src_h,
      78             :                                      const struct drm_framebuffer *fb)
      79             : {
      80             :         unsigned int fb_width, fb_height;
      81             : 
      82           0 :         fb_width = fb->width << 16;
      83           0 :         fb_height = fb->height << 16;
      84             : 
      85             :         /* Make sure source coordinates are inside the fb. */
      86           0 :         if (src_w > fb_width ||
      87           0 :             src_x > fb_width - src_w ||
      88           0 :             src_h > fb_height ||
      89           0 :             src_y > fb_height - src_h) {
      90           0 :                 drm_dbg_kms(fb->dev, "Invalid source coordinates "
      91             :                             "%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
      92             :                             src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
      93             :                             src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
      94             :                             src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
      95             :                             src_y >> 16, ((src_y & 0xffff) * 15625) >> 10,
      96             :                             fb->width, fb->height);
      97           0 :                 return -ENOSPC;
      98             :         }
      99             : 
     100             :         return 0;
     101             : }
     102             : 
     103             : /**
     104             :  * drm_mode_addfb - add an FB to the graphics configuration
     105             :  * @dev: drm device for the ioctl
     106             :  * @or: pointer to request structure
     107             :  * @file_priv: drm file
     108             :  *
     109             :  * Add a new FB to the specified CRTC, given a user request. This is the
     110             :  * original addfb ioctl which only supported RGB formats.
     111             :  *
     112             :  * Called by the user via ioctl, or by an in-kernel client.
     113             :  *
     114             :  * Returns:
     115             :  * Zero on success, negative errno on failure.
     116             :  */
     117           0 : int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
     118             :                    struct drm_file *file_priv)
     119             : {
     120           0 :         struct drm_mode_fb_cmd2 r = {};
     121             :         int ret;
     122             : 
     123           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     124             :                 return -EOPNOTSUPP;
     125             : 
     126           0 :         r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
     127           0 :         if (r.pixel_format == DRM_FORMAT_INVALID) {
     128           0 :                 drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
     129           0 :                 return -EINVAL;
     130             :         }
     131             : 
     132             :         /* convert to new format and call new ioctl */
     133           0 :         r.fb_id = or->fb_id;
     134           0 :         r.width = or->width;
     135           0 :         r.height = or->height;
     136           0 :         r.pitches[0] = or->pitch;
     137           0 :         r.handles[0] = or->handle;
     138             : 
     139           0 :         ret = drm_mode_addfb2(dev, &r, file_priv);
     140           0 :         if (ret)
     141             :                 return ret;
     142             : 
     143           0 :         or->fb_id = r.fb_id;
     144             : 
     145           0 :         return 0;
     146             : }
     147             : 
     148           0 : int drm_mode_addfb_ioctl(struct drm_device *dev,
     149             :                          void *data, struct drm_file *file_priv)
     150             : {
     151           0 :         return drm_mode_addfb(dev, data, file_priv);
     152             : }
     153             : 
     154             : static int fb_plane_width(int width,
     155             :                           const struct drm_format_info *format, int plane)
     156             : {
     157          69 :         if (plane == 0)
     158             :                 return width;
     159             : 
     160          26 :         return DIV_ROUND_UP(width, format->hsub);
     161             : }
     162             : 
     163             : static int fb_plane_height(int height,
     164             :                            const struct drm_format_info *format, int plane)
     165             : {
     166          69 :         if (plane == 0)
     167             :                 return height;
     168             : 
     169          26 :         return DIV_ROUND_UP(height, format->vsub);
     170             : }
     171             : 
     172          44 : static int framebuffer_check(struct drm_device *dev,
     173             :                              const struct drm_mode_fb_cmd2 *r)
     174             : {
     175             :         const struct drm_format_info *info;
     176             :         int i;
     177             : 
     178             :         /* check if the format is supported at all */
     179          44 :         if (!__drm_format_info(r->pixel_format)) {
     180           1 :                 drm_dbg_kms(dev, "bad framebuffer format %p4cc\n",
     181             :                             &r->pixel_format);
     182           1 :                 return -EINVAL;
     183             :         }
     184             : 
     185          43 :         if (r->width == 0) {
     186           0 :                 drm_dbg_kms(dev, "bad framebuffer width %u\n", r->width);
     187           0 :                 return -EINVAL;
     188             :         }
     189             : 
     190          43 :         if (r->height == 0) {
     191           0 :                 drm_dbg_kms(dev, "bad framebuffer height %u\n", r->height);
     192           0 :                 return -EINVAL;
     193             :         }
     194             : 
     195             :         /* now let the driver pick its own format info */
     196          43 :         info = drm_get_format_info(dev, r);
     197             : 
     198          97 :         for (i = 0; i < info->num_planes; i++) {
     199         138 :                 unsigned int width = fb_plane_width(r->width, info, i);
     200         138 :                 unsigned int height = fb_plane_height(r->height, info, i);
     201          69 :                 unsigned int block_size = info->char_per_block[i];
     202          69 :                 u64 min_pitch = drm_format_info_min_pitch(info, i, width);
     203             : 
     204          69 :                 if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
     205           0 :                         drm_dbg_kms(dev, "Format requires non-linear modifier for plane %d\n", i);
     206           0 :                         return -EINVAL;
     207             :                 }
     208             : 
     209          69 :                 if (!r->handles[i]) {
     210           1 :                         drm_dbg_kms(dev, "no buffer object handle for plane %d\n", i);
     211           1 :                         return -EINVAL;
     212             :                 }
     213             : 
     214          68 :                 if (min_pitch > UINT_MAX)
     215             :                         return -ERANGE;
     216             : 
     217          68 :                 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
     218             :                         return -ERANGE;
     219             : 
     220          67 :                 if (block_size && r->pitches[i] < min_pitch) {
     221           4 :                         drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i);
     222           4 :                         return -EINVAL;
     223             :                 }
     224             : 
     225          63 :                 if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
     226           5 :                         drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
     227             :                                     r->modifier[i], i);
     228           5 :                         return -EINVAL;
     229             :                 }
     230             : 
     231          87 :                 if (r->flags & DRM_MODE_FB_MODIFIERS &&
     232          29 :                     r->modifier[i] != r->modifier[0]) {
     233           3 :                         drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
     234             :                                     r->modifier[i], i);
     235           3 :                         return -EINVAL;
     236             :                 }
     237             : 
     238             :                 /* modifier specific checks: */
     239          55 :                 switch (r->modifier[i]) {
     240             :                 case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE:
     241             :                         /* NOTE: the pitch restriction may be lifted later if it turns
     242             :                          * out that no hw has this restriction:
     243             :                          */
     244          11 :                         if (r->pixel_format != DRM_FORMAT_NV12 ||
     245          15 :                                         width % 128 || height % 32 ||
     246           5 :                                         r->pitches[i] % 128) {
     247           1 :                                 drm_dbg_kms(dev, "bad modifier data for plane %d\n", i);
     248           1 :                                 return -EINVAL;
     249             :                         }
     250             :                         break;
     251             : 
     252             :                 default:
     253             :                         break;
     254             :                 }
     255             :         }
     256             : 
     257          50 :         for (i = info->num_planes; i < 4; i++) {
     258          56 :                 if (r->modifier[i]) {
     259           3 :                         drm_dbg_kms(dev, "non-zero modifier for unused plane %d\n", i);
     260           3 :                         return -EINVAL;
     261             :                 }
     262             : 
     263             :                 /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */
     264          53 :                 if (!(r->flags & DRM_MODE_FB_MODIFIERS))
     265          37 :                         continue;
     266             : 
     267          16 :                 if (r->handles[i]) {
     268           2 :                         drm_dbg_kms(dev, "buffer object handle for unused plane %d\n", i);
     269           2 :                         return -EINVAL;
     270             :                 }
     271             : 
     272          14 :                 if (r->pitches[i]) {
     273           1 :                         drm_dbg_kms(dev, "non-zero pitch for unused plane %d\n", i);
     274           1 :                         return -EINVAL;
     275             :                 }
     276             : 
     277          13 :                 if (r->offsets[i]) {
     278           0 :                         drm_dbg_kms(dev, "non-zero offset for unused plane %d\n", i);
     279           0 :                         return -EINVAL;
     280             :                 }
     281             :         }
     282             : 
     283             :         return 0;
     284             : }
     285             : 
     286             : struct drm_framebuffer *
     287          47 : drm_internal_framebuffer_create(struct drm_device *dev,
     288             :                                 const struct drm_mode_fb_cmd2 *r,
     289             :                                 struct drm_file *file_priv)
     290             : {
     291          47 :         struct drm_mode_config *config = &dev->mode_config;
     292             :         struct drm_framebuffer *fb;
     293             :         int ret;
     294             : 
     295          47 :         if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
     296           0 :                 drm_dbg_kms(dev, "bad framebuffer flags 0x%08x\n", r->flags);
     297           0 :                 return ERR_PTR(-EINVAL);
     298             :         }
     299             : 
     300          47 :         if ((config->min_width > r->width) || (r->width > config->max_width)) {
     301           2 :                 drm_dbg_kms(dev, "bad framebuffer width %d, should be >= %d && <= %d\n",
     302             :                             r->width, config->min_width, config->max_width);
     303           2 :                 return ERR_PTR(-EINVAL);
     304             :         }
     305          45 :         if ((config->min_height > r->height) || (r->height > config->max_height)) {
     306           1 :                 drm_dbg_kms(dev, "bad framebuffer height %d, should be >= %d && <= %d\n",
     307             :                             r->height, config->min_height, config->max_height);
     308           1 :                 return ERR_PTR(-EINVAL);
     309             :         }
     310             : 
     311          60 :         if (r->flags & DRM_MODE_FB_MODIFIERS &&
     312          16 :             dev->mode_config.fb_modifiers_not_supported) {
     313           0 :                 drm_dbg_kms(dev, "driver does not support fb modifiers\n");
     314           0 :                 return ERR_PTR(-EINVAL);
     315             :         }
     316             : 
     317          44 :         ret = framebuffer_check(dev, r);
     318          44 :         if (ret)
     319          44 :                 return ERR_PTR(ret);
     320             : 
     321          22 :         fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
     322          22 :         if (IS_ERR(fb)) {
     323          22 :                 drm_dbg_kms(dev, "could not create framebuffer\n");
     324          22 :                 return fb;
     325             :         }
     326             : 
     327             :         return fb;
     328             : }
     329             : EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create);
     330             : 
     331             : /**
     332             :  * drm_mode_addfb2 - add an FB to the graphics configuration
     333             :  * @dev: drm device for the ioctl
     334             :  * @data: data pointer for the ioctl
     335             :  * @file_priv: drm file for the ioctl call
     336             :  *
     337             :  * Add a new FB to the specified CRTC, given a user request with format. This is
     338             :  * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
     339             :  * and uses fourcc codes as pixel format specifiers.
     340             :  *
     341             :  * Called by the user via ioctl.
     342             :  *
     343             :  * Returns:
     344             :  * Zero on success, negative errno on failure.
     345             :  */
     346           0 : int drm_mode_addfb2(struct drm_device *dev,
     347             :                     void *data, struct drm_file *file_priv)
     348             : {
     349           0 :         struct drm_mode_fb_cmd2 *r = data;
     350             :         struct drm_framebuffer *fb;
     351             : 
     352           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     353             :                 return -EOPNOTSUPP;
     354             : 
     355           0 :         fb = drm_internal_framebuffer_create(dev, r, file_priv);
     356           0 :         if (IS_ERR(fb))
     357           0 :                 return PTR_ERR(fb);
     358             : 
     359           0 :         drm_dbg_kms(dev, "[FB:%d]\n", fb->base.id);
     360           0 :         r->fb_id = fb->base.id;
     361             : 
     362             :         /* Transfer ownership to the filp for reaping on close */
     363           0 :         mutex_lock(&file_priv->fbs_lock);
     364           0 :         list_add(&fb->filp_head, &file_priv->fbs);
     365           0 :         mutex_unlock(&file_priv->fbs_lock);
     366             : 
     367           0 :         return 0;
     368             : }
     369             : 
     370           0 : int drm_mode_addfb2_ioctl(struct drm_device *dev,
     371             :                           void *data, struct drm_file *file_priv)
     372             : {
     373             : #ifdef __BIG_ENDIAN
     374             :         if (!dev->mode_config.quirk_addfb_prefer_host_byte_order) {
     375             :                 /*
     376             :                  * Drivers must set the
     377             :                  * quirk_addfb_prefer_host_byte_order quirk to make
     378             :                  * the drm_mode_addfb() compat code work correctly on
     379             :                  * bigendian machines.
     380             :                  *
     381             :                  * If they don't they interpret pixel_format values
     382             :                  * incorrectly for bug compatibility, which in turn
     383             :                  * implies the ADDFB2 ioctl does not work correctly
     384             :                  * then.  So block it to make userspace fallback to
     385             :                  * ADDFB.
     386             :                  */
     387             :                 drm_dbg_kms(dev, "addfb2 broken on bigendian");
     388             :                 return -EOPNOTSUPP;
     389             :         }
     390             : #endif
     391           0 :         return drm_mode_addfb2(dev, data, file_priv);
     392             : }
     393             : 
     394             : struct drm_mode_rmfb_work {
     395             :         struct work_struct work;
     396             :         struct list_head fbs;
     397             : };
     398             : 
     399           0 : static void drm_mode_rmfb_work_fn(struct work_struct *w)
     400             : {
     401           0 :         struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work);
     402             : 
     403           0 :         while (!list_empty(&arg->fbs)) {
     404           0 :                 struct drm_framebuffer *fb =
     405           0 :                         list_first_entry(&arg->fbs, typeof(*fb), filp_head);
     406             : 
     407           0 :                 drm_dbg_kms(fb->dev,
     408             :                             "Removing [FB:%d] from all active usage due to RMFB ioctl\n",
     409             :                             fb->base.id);
     410           0 :                 list_del_init(&fb->filp_head);
     411           0 :                 drm_framebuffer_remove(fb);
     412             :         }
     413           0 : }
     414             : 
     415             : /**
     416             :  * drm_mode_rmfb - remove an FB from the configuration
     417             :  * @dev: drm device
     418             :  * @fb_id: id of framebuffer to remove
     419             :  * @file_priv: drm file
     420             :  *
     421             :  * Remove the specified FB.
     422             :  *
     423             :  * Called by the user via ioctl, or by an in-kernel client.
     424             :  *
     425             :  * Returns:
     426             :  * Zero on success, negative errno on failure.
     427             :  */
     428           0 : int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
     429             :                   struct drm_file *file_priv)
     430             : {
     431           0 :         struct drm_framebuffer *fb = NULL;
     432           0 :         struct drm_framebuffer *fbl = NULL;
     433           0 :         int found = 0;
     434             : 
     435           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     436             :                 return -EOPNOTSUPP;
     437             : 
     438           0 :         fb = drm_framebuffer_lookup(dev, file_priv, fb_id);
     439           0 :         if (!fb)
     440             :                 return -ENOENT;
     441             : 
     442           0 :         mutex_lock(&file_priv->fbs_lock);
     443           0 :         list_for_each_entry(fbl, &file_priv->fbs, filp_head)
     444           0 :                 if (fb == fbl)
     445           0 :                         found = 1;
     446           0 :         if (!found) {
     447           0 :                 mutex_unlock(&file_priv->fbs_lock);
     448             :                 goto fail_unref;
     449             :         }
     450             : 
     451           0 :         list_del_init(&fb->filp_head);
     452           0 :         mutex_unlock(&file_priv->fbs_lock);
     453             : 
     454             :         /* drop the reference we picked up in framebuffer lookup */
     455           0 :         drm_framebuffer_put(fb);
     456             : 
     457             :         /*
     458             :          * we now own the reference that was stored in the fbs list
     459             :          *
     460             :          * drm_framebuffer_remove may fail with -EINTR on pending signals,
     461             :          * so run this in a separate stack as there's no way to correctly
     462             :          * handle this after the fb is already removed from the lookup table.
     463             :          */
     464           0 :         if (drm_framebuffer_read_refcount(fb) > 1) {
     465             :                 struct drm_mode_rmfb_work arg;
     466             : 
     467           0 :                 INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
     468           0 :                 INIT_LIST_HEAD(&arg.fbs);
     469           0 :                 list_add_tail(&fb->filp_head, &arg.fbs);
     470             : 
     471           0 :                 schedule_work(&arg.work);
     472           0 :                 flush_work(&arg.work);
     473           0 :                 destroy_work_on_stack(&arg.work);
     474             :         } else
     475             :                 drm_framebuffer_put(fb);
     476             : 
     477             :         return 0;
     478             : 
     479             : fail_unref:
     480           0 :         drm_framebuffer_put(fb);
     481           0 :         return -ENOENT;
     482             : }
     483             : 
     484           0 : int drm_mode_rmfb_ioctl(struct drm_device *dev,
     485             :                         void *data, struct drm_file *file_priv)
     486             : {
     487           0 :         uint32_t *fb_id = data;
     488             : 
     489           0 :         return drm_mode_rmfb(dev, *fb_id, file_priv);
     490             : }
     491             : 
     492             : /**
     493             :  * drm_mode_getfb - get FB info
     494             :  * @dev: drm device for the ioctl
     495             :  * @data: data pointer for the ioctl
     496             :  * @file_priv: drm file for the ioctl call
     497             :  *
     498             :  * Lookup the FB given its ID and return info about it.
     499             :  *
     500             :  * Called by the user via ioctl.
     501             :  *
     502             :  * Returns:
     503             :  * Zero on success, negative errno on failure.
     504             :  */
     505           0 : int drm_mode_getfb(struct drm_device *dev,
     506             :                    void *data, struct drm_file *file_priv)
     507             : {
     508           0 :         struct drm_mode_fb_cmd *r = data;
     509             :         struct drm_framebuffer *fb;
     510             :         int ret;
     511             : 
     512           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     513             :                 return -EOPNOTSUPP;
     514             : 
     515           0 :         fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
     516           0 :         if (!fb)
     517             :                 return -ENOENT;
     518             : 
     519             :         /* Multi-planar framebuffers need getfb2. */
     520           0 :         if (fb->format->num_planes > 1) {
     521             :                 ret = -EINVAL;
     522             :                 goto out;
     523             :         }
     524             : 
     525           0 :         if (!fb->funcs->create_handle) {
     526             :                 ret = -ENODEV;
     527             :                 goto out;
     528             :         }
     529             : 
     530           0 :         r->height = fb->height;
     531           0 :         r->width = fb->width;
     532           0 :         r->depth = fb->format->depth;
     533           0 :         r->bpp = drm_format_info_bpp(fb->format, 0);
     534           0 :         r->pitch = fb->pitches[0];
     535             : 
     536             :         /* GET_FB() is an unprivileged ioctl so we must not return a
     537             :          * buffer-handle to non-master processes! For
     538             :          * backwards-compatibility reasons, we cannot make GET_FB() privileged,
     539             :          * so just return an invalid handle for non-masters.
     540             :          */
     541           0 :         if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) {
     542           0 :                 r->handle = 0;
     543           0 :                 ret = 0;
     544           0 :                 goto out;
     545             :         }
     546             : 
     547           0 :         ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
     548             : 
     549             : out:
     550           0 :         drm_framebuffer_put(fb);
     551           0 :         return ret;
     552             : }
     553             : 
     554             : /**
     555             :  * drm_mode_getfb2_ioctl - get extended FB info
     556             :  * @dev: drm device for the ioctl
     557             :  * @data: data pointer for the ioctl
     558             :  * @file_priv: drm file for the ioctl call
     559             :  *
     560             :  * Lookup the FB given its ID and return info about it.
     561             :  *
     562             :  * Called by the user via ioctl.
     563             :  *
     564             :  * Returns:
     565             :  * Zero on success, negative errno on failure.
     566             :  */
     567           0 : int drm_mode_getfb2_ioctl(struct drm_device *dev,
     568             :                           void *data, struct drm_file *file_priv)
     569             : {
     570           0 :         struct drm_mode_fb_cmd2 *r = data;
     571             :         struct drm_framebuffer *fb;
     572             :         unsigned int i;
     573             :         int ret;
     574             : 
     575           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     576             :                 return -EINVAL;
     577             : 
     578           0 :         fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
     579           0 :         if (!fb)
     580             :                 return -ENOENT;
     581             : 
     582             :         /* For multi-plane framebuffers, we require the driver to place the
     583             :          * GEM objects directly in the drm_framebuffer. For single-plane
     584             :          * framebuffers, we can fall back to create_handle.
     585             :          */
     586           0 :         if (!fb->obj[0] &&
     587           0 :             (fb->format->num_planes > 1 || !fb->funcs->create_handle)) {
     588             :                 ret = -ENODEV;
     589             :                 goto out;
     590             :         }
     591             : 
     592           0 :         r->height = fb->height;
     593           0 :         r->width = fb->width;
     594           0 :         r->pixel_format = fb->format->format;
     595             : 
     596           0 :         r->flags = 0;
     597           0 :         if (!dev->mode_config.fb_modifiers_not_supported)
     598           0 :                 r->flags |= DRM_MODE_FB_MODIFIERS;
     599             : 
     600           0 :         for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
     601           0 :                 r->handles[i] = 0;
     602           0 :                 r->pitches[i] = 0;
     603           0 :                 r->offsets[i] = 0;
     604           0 :                 r->modifier[i] = 0;
     605             :         }
     606             : 
     607           0 :         for (i = 0; i < fb->format->num_planes; i++) {
     608           0 :                 r->pitches[i] = fb->pitches[i];
     609           0 :                 r->offsets[i] = fb->offsets[i];
     610           0 :                 if (!dev->mode_config.fb_modifiers_not_supported)
     611           0 :                         r->modifier[i] = fb->modifier;
     612             :         }
     613             : 
     614             :         /* GET_FB2() is an unprivileged ioctl so we must not return a
     615             :          * buffer-handle to non master/root processes! To match GET_FB()
     616             :          * just return invalid handles (0) for non masters/root
     617             :          * rather than making GET_FB2() privileged.
     618             :          */
     619           0 :         if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) {
     620             :                 ret = 0;
     621             :                 goto out;
     622             :         }
     623             : 
     624           0 :         for (i = 0; i < fb->format->num_planes; i++) {
     625             :                 int j;
     626             : 
     627             :                 /* If we reuse the same object for multiple planes, also
     628             :                  * return the same handle.
     629             :                  */
     630           0 :                 for (j = 0; j < i; j++) {
     631           0 :                         if (fb->obj[i] == fb->obj[j]) {
     632           0 :                                 r->handles[i] = r->handles[j];
     633           0 :                                 break;
     634             :                         }
     635             :                 }
     636             : 
     637           0 :                 if (r->handles[i])
     638           0 :                         continue;
     639             : 
     640           0 :                 if (fb->obj[i]) {
     641           0 :                         ret = drm_gem_handle_create(file_priv, fb->obj[i],
     642           0 :                                                     &r->handles[i]);
     643             :                 } else {
     644           0 :                         WARN_ON(i > 0);
     645           0 :                         ret = fb->funcs->create_handle(fb, file_priv,
     646           0 :                                                        &r->handles[i]);
     647             :                 }
     648             : 
     649           0 :                 if (ret != 0)
     650             :                         goto out;
     651             :         }
     652             : 
     653             : out:
     654           0 :         if (ret != 0) {
     655             :                 /* Delete any previously-created handles on failure. */
     656           0 :                 for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
     657             :                         int j;
     658             : 
     659           0 :                         if (r->handles[i])
     660           0 :                                 drm_gem_handle_delete(file_priv, r->handles[i]);
     661             : 
     662             :                         /* Zero out any handles identical to the one we just
     663             :                          * deleted.
     664             :                          */
     665           0 :                         for (j = i + 1; j < ARRAY_SIZE(r->handles); j++) {
     666           0 :                                 if (r->handles[j] == r->handles[i])
     667           0 :                                         r->handles[j] = 0;
     668             :                         }
     669             :                 }
     670             :         }
     671             : 
     672           0 :         drm_framebuffer_put(fb);
     673           0 :         return ret;
     674             : }
     675             : 
     676             : /**
     677             :  * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
     678             :  * @dev: drm device for the ioctl
     679             :  * @data: data pointer for the ioctl
     680             :  * @file_priv: drm file for the ioctl call
     681             :  *
     682             :  * Lookup the FB and flush out the damaged area supplied by userspace as a clip
     683             :  * rectangle list. Generic userspace which does frontbuffer rendering must call
     684             :  * this ioctl to flush out the changes on manual-update display outputs, e.g.
     685             :  * usb display-link, mipi manual update panels or edp panel self refresh modes.
     686             :  *
     687             :  * Modesetting drivers which always update the frontbuffer do not need to
     688             :  * implement the corresponding &drm_framebuffer_funcs.dirty callback.
     689             :  *
     690             :  * Called by the user via ioctl.
     691             :  *
     692             :  * Returns:
     693             :  * Zero on success, negative errno on failure.
     694             :  */
     695           0 : int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
     696             :                            void *data, struct drm_file *file_priv)
     697             : {
     698             :         struct drm_clip_rect __user *clips_ptr;
     699           0 :         struct drm_clip_rect *clips = NULL;
     700           0 :         struct drm_mode_fb_dirty_cmd *r = data;
     701             :         struct drm_framebuffer *fb;
     702             :         unsigned flags;
     703             :         int num_clips;
     704             :         int ret;
     705             : 
     706           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     707             :                 return -EOPNOTSUPP;
     708             : 
     709           0 :         fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
     710           0 :         if (!fb)
     711             :                 return -ENOENT;
     712             : 
     713           0 :         num_clips = r->num_clips;
     714           0 :         clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
     715             : 
     716           0 :         if (!num_clips != !clips_ptr) {
     717             :                 ret = -EINVAL;
     718             :                 goto out_err1;
     719             :         }
     720             : 
     721           0 :         flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
     722             : 
     723             :         /* If userspace annotates copy, clips must come in pairs */
     724           0 :         if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
     725             :                 ret = -EINVAL;
     726             :                 goto out_err1;
     727             :         }
     728             : 
     729           0 :         if (num_clips && clips_ptr) {
     730           0 :                 if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
     731             :                         ret = -EINVAL;
     732             :                         goto out_err1;
     733             :                 }
     734           0 :                 clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
     735           0 :                 if (!clips) {
     736             :                         ret = -ENOMEM;
     737             :                         goto out_err1;
     738             :                 }
     739             : 
     740           0 :                 ret = copy_from_user(clips, clips_ptr,
     741             :                                      num_clips * sizeof(*clips));
     742           0 :                 if (ret) {
     743             :                         ret = -EFAULT;
     744             :                         goto out_err2;
     745             :                 }
     746             :         }
     747             : 
     748           0 :         if (fb->funcs->dirty) {
     749           0 :                 ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
     750             :                                        clips, num_clips);
     751             :         } else {
     752             :                 ret = -ENOSYS;
     753             :         }
     754             : 
     755             : out_err2:
     756           0 :         kfree(clips);
     757             : out_err1:
     758           0 :         drm_framebuffer_put(fb);
     759             : 
     760           0 :         return ret;
     761             : }
     762             : 
     763             : /**
     764             :  * drm_fb_release - remove and free the FBs on this file
     765             :  * @priv: drm file for the ioctl
     766             :  *
     767             :  * Destroy all the FBs associated with @filp.
     768             :  *
     769             :  * Called by the user via ioctl.
     770             :  *
     771             :  * Returns:
     772             :  * Zero on success, negative errno on failure.
     773             :  */
     774           0 : void drm_fb_release(struct drm_file *priv)
     775             : {
     776             :         struct drm_framebuffer *fb, *tfb;
     777             :         struct drm_mode_rmfb_work arg;
     778             : 
     779           0 :         INIT_LIST_HEAD(&arg.fbs);
     780             : 
     781             :         /*
     782             :          * When the file gets released that means no one else can access the fb
     783             :          * list any more, so no need to grab fpriv->fbs_lock. And we need to
     784             :          * avoid upsetting lockdep since the universal cursor code adds a
     785             :          * framebuffer while holding mutex locks.
     786             :          *
     787             :          * Note that a real deadlock between fpriv->fbs_lock and the modeset
     788             :          * locks is impossible here since no one else but this function can get
     789             :          * at it any more.
     790             :          */
     791           0 :         list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
     792           0 :                 if (drm_framebuffer_read_refcount(fb) > 1) {
     793           0 :                         list_move_tail(&fb->filp_head, &arg.fbs);
     794             :                 } else {
     795           0 :                         list_del_init(&fb->filp_head);
     796             : 
     797             :                         /* This drops the fpriv->fbs reference. */
     798             :                         drm_framebuffer_put(fb);
     799             :                 }
     800             :         }
     801             : 
     802           0 :         if (!list_empty(&arg.fbs)) {
     803           0 :                 INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
     804             : 
     805           0 :                 schedule_work(&arg.work);
     806           0 :                 flush_work(&arg.work);
     807           0 :                 destroy_work_on_stack(&arg.work);
     808             :         }
     809           0 : }
     810             : 
     811           0 : void drm_framebuffer_free(struct kref *kref)
     812             : {
     813           0 :         struct drm_framebuffer *fb =
     814           0 :                         container_of(kref, struct drm_framebuffer, base.refcount);
     815           0 :         struct drm_device *dev = fb->dev;
     816             : 
     817             :         /*
     818             :          * The lookup idr holds a weak reference, which has not necessarily been
     819             :          * removed at this point. Check for that.
     820             :          */
     821           0 :         drm_mode_object_unregister(dev, &fb->base);
     822             : 
     823           0 :         fb->funcs->destroy(fb);
     824           0 : }
     825             : 
     826             : /**
     827             :  * drm_framebuffer_init - initialize a framebuffer
     828             :  * @dev: DRM device
     829             :  * @fb: framebuffer to be initialized
     830             :  * @funcs: ... with these functions
     831             :  *
     832             :  * Allocates an ID for the framebuffer's parent mode object, sets its mode
     833             :  * functions & device file and adds it to the master fd list.
     834             :  *
     835             :  * IMPORTANT:
     836             :  * This functions publishes the fb and makes it available for concurrent access
     837             :  * by other users. Which means by this point the fb _must_ be fully set up -
     838             :  * since all the fb attributes are invariant over its lifetime, no further
     839             :  * locking but only correct reference counting is required.
     840             :  *
     841             :  * Returns:
     842             :  * Zero on success, error code on failure.
     843             :  */
     844           0 : int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
     845             :                          const struct drm_framebuffer_funcs *funcs)
     846             : {
     847             :         int ret;
     848             : 
     849           0 :         if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
     850             :                 return -EINVAL;
     851             : 
     852           0 :         INIT_LIST_HEAD(&fb->filp_head);
     853             : 
     854           0 :         fb->funcs = funcs;
     855           0 :         strcpy(fb->comm, current->comm);
     856             : 
     857           0 :         ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
     858             :                                     false, drm_framebuffer_free);
     859           0 :         if (ret)
     860             :                 goto out;
     861             : 
     862           0 :         mutex_lock(&dev->mode_config.fb_lock);
     863           0 :         dev->mode_config.num_fb++;
     864           0 :         list_add(&fb->head, &dev->mode_config.fb_list);
     865           0 :         mutex_unlock(&dev->mode_config.fb_lock);
     866             : 
     867           0 :         drm_mode_object_register(dev, &fb->base);
     868             : out:
     869             :         return ret;
     870             : }
     871             : EXPORT_SYMBOL(drm_framebuffer_init);
     872             : 
     873             : /**
     874             :  * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
     875             :  * @dev: drm device
     876             :  * @file_priv: drm file to check for lease against.
     877             :  * @id: id of the fb object
     878             :  *
     879             :  * If successful, this grabs an additional reference to the framebuffer -
     880             :  * callers need to make sure to eventually unreference the returned framebuffer
     881             :  * again, using drm_framebuffer_put().
     882             :  */
     883           0 : struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
     884             :                                                struct drm_file *file_priv,
     885             :                                                uint32_t id)
     886             : {
     887             :         struct drm_mode_object *obj;
     888           0 :         struct drm_framebuffer *fb = NULL;
     889             : 
     890           0 :         obj = __drm_mode_object_find(dev, file_priv, id, DRM_MODE_OBJECT_FB);
     891           0 :         if (obj)
     892           0 :                 fb = obj_to_fb(obj);
     893           0 :         return fb;
     894             : }
     895             : EXPORT_SYMBOL(drm_framebuffer_lookup);
     896             : 
     897             : /**
     898             :  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
     899             :  * @fb: fb to unregister
     900             :  *
     901             :  * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
     902             :  * those used for fbdev. Note that the caller must hold a reference of its own,
     903             :  * i.e. the object may not be destroyed through this call (since it'll lead to a
     904             :  * locking inversion).
     905             :  *
     906             :  * NOTE: This function is deprecated. For driver-private framebuffers it is not
     907             :  * recommended to embed a framebuffer struct info fbdev struct, instead, a
     908             :  * framebuffer pointer is preferred and drm_framebuffer_put() should be called
     909             :  * when the framebuffer is to be cleaned up.
     910             :  */
     911           0 : void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
     912             : {
     913             :         struct drm_device *dev;
     914             : 
     915           0 :         if (!fb)
     916             :                 return;
     917             : 
     918           0 :         dev = fb->dev;
     919             : 
     920             :         /* Mark fb as reaped and drop idr ref. */
     921           0 :         drm_mode_object_unregister(dev, &fb->base);
     922             : }
     923             : EXPORT_SYMBOL(drm_framebuffer_unregister_private);
     924             : 
     925             : /**
     926             :  * drm_framebuffer_cleanup - remove a framebuffer object
     927             :  * @fb: framebuffer to remove
     928             :  *
     929             :  * Cleanup framebuffer. This function is intended to be used from the drivers
     930             :  * &drm_framebuffer_funcs.destroy callback. It can also be used to clean up
     931             :  * driver private framebuffers embedded into a larger structure.
     932             :  *
     933             :  * Note that this function does not remove the fb from active usage - if it is
     934             :  * still used anywhere, hilarity can ensue since userspace could call getfb on
     935             :  * the id and get back -EINVAL. Obviously no concern at driver unload time.
     936             :  *
     937             :  * Also, the framebuffer will not be removed from the lookup idr - for
     938             :  * user-created framebuffers this will happen in the rmfb ioctl. For
     939             :  * driver-private objects (e.g. for fbdev) drivers need to explicitly call
     940             :  * drm_framebuffer_unregister_private.
     941             :  */
     942           0 : void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
     943             : {
     944           0 :         struct drm_device *dev = fb->dev;
     945             : 
     946           0 :         mutex_lock(&dev->mode_config.fb_lock);
     947           0 :         list_del(&fb->head);
     948           0 :         dev->mode_config.num_fb--;
     949           0 :         mutex_unlock(&dev->mode_config.fb_lock);
     950           0 : }
     951             : EXPORT_SYMBOL(drm_framebuffer_cleanup);
     952             : 
     953           0 : static int atomic_remove_fb(struct drm_framebuffer *fb)
     954             : {
     955             :         struct drm_modeset_acquire_ctx ctx;
     956           0 :         struct drm_device *dev = fb->dev;
     957             :         struct drm_atomic_state *state;
     958             :         struct drm_plane *plane;
     959             :         struct drm_connector *conn __maybe_unused;
     960             :         struct drm_connector_state *conn_state;
     961             :         int i, ret;
     962             :         unsigned plane_mask;
     963           0 :         bool disable_crtcs = false;
     964             : 
     965             : retry_disable:
     966           0 :         drm_modeset_acquire_init(&ctx, 0);
     967             : 
     968           0 :         state = drm_atomic_state_alloc(dev);
     969           0 :         if (!state) {
     970             :                 ret = -ENOMEM;
     971             :                 goto out;
     972             :         }
     973           0 :         state->acquire_ctx = &ctx;
     974             : 
     975             : retry:
     976           0 :         plane_mask = 0;
     977           0 :         ret = drm_modeset_lock_all_ctx(dev, &ctx);
     978           0 :         if (ret)
     979             :                 goto unlock;
     980             : 
     981           0 :         drm_for_each_plane(plane, dev) {
     982             :                 struct drm_plane_state *plane_state;
     983             : 
     984           0 :                 if (plane->state->fb != fb)
     985           0 :                         continue;
     986             : 
     987           0 :                 drm_dbg_kms(dev,
     988             :                             "Disabling [PLANE:%d:%s] because [FB:%d] is removed\n",
     989             :                             plane->base.id, plane->name, fb->base.id);
     990             : 
     991           0 :                 plane_state = drm_atomic_get_plane_state(state, plane);
     992           0 :                 if (IS_ERR(plane_state)) {
     993           0 :                         ret = PTR_ERR(plane_state);
     994           0 :                         goto unlock;
     995             :                 }
     996             : 
     997           0 :                 if (disable_crtcs && plane_state->crtc->primary == plane) {
     998             :                         struct drm_crtc_state *crtc_state;
     999             : 
    1000           0 :                         drm_dbg_kms(dev,
    1001             :                                     "Disabling [CRTC:%d:%s] because [FB:%d] is removed\n",
    1002             :                                     plane_state->crtc->base.id,
    1003             :                                     plane_state->crtc->name, fb->base.id);
    1004             : 
    1005           0 :                         crtc_state = drm_atomic_get_existing_crtc_state(state, plane_state->crtc);
    1006             : 
    1007           0 :                         ret = drm_atomic_add_affected_connectors(state, plane_state->crtc);
    1008           0 :                         if (ret)
    1009             :                                 goto unlock;
    1010             : 
    1011           0 :                         crtc_state->active = false;
    1012           0 :                         ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
    1013           0 :                         if (ret)
    1014             :                                 goto unlock;
    1015             :                 }
    1016             : 
    1017           0 :                 drm_atomic_set_fb_for_plane(plane_state, NULL);
    1018           0 :                 ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
    1019           0 :                 if (ret)
    1020             :                         goto unlock;
    1021             : 
    1022           0 :                 plane_mask |= drm_plane_mask(plane);
    1023             :         }
    1024             : 
    1025             :         /* This list is only filled when disable_crtcs is set. */
    1026           0 :         for_each_new_connector_in_state(state, conn, conn_state, i) {
    1027           0 :                 ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
    1028             : 
    1029           0 :                 if (ret)
    1030             :                         goto unlock;
    1031             :         }
    1032             : 
    1033           0 :         if (plane_mask)
    1034           0 :                 ret = drm_atomic_commit(state);
    1035             : 
    1036             : unlock:
    1037           0 :         if (ret == -EDEADLK) {
    1038           0 :                 drm_atomic_state_clear(state);
    1039           0 :                 drm_modeset_backoff(&ctx);
    1040           0 :                 goto retry;
    1041             :         }
    1042             : 
    1043             :         drm_atomic_state_put(state);
    1044             : 
    1045             : out:
    1046           0 :         drm_modeset_drop_locks(&ctx);
    1047           0 :         drm_modeset_acquire_fini(&ctx);
    1048             : 
    1049           0 :         if (ret == -EINVAL && !disable_crtcs) {
    1050             :                 disable_crtcs = true;
    1051             :                 goto retry_disable;
    1052             :         }
    1053             : 
    1054           0 :         return ret;
    1055             : }
    1056             : 
    1057           0 : static void legacy_remove_fb(struct drm_framebuffer *fb)
    1058             : {
    1059           0 :         struct drm_device *dev = fb->dev;
    1060             :         struct drm_crtc *crtc;
    1061             :         struct drm_plane *plane;
    1062             : 
    1063           0 :         drm_modeset_lock_all(dev);
    1064             :         /* remove from any CRTC */
    1065           0 :         drm_for_each_crtc(crtc, dev) {
    1066           0 :                 if (crtc->primary->fb == fb) {
    1067           0 :                         drm_dbg_kms(dev,
    1068             :                                     "Disabling [CRTC:%d:%s] because [FB:%d] is removed\n",
    1069             :                                     crtc->base.id, crtc->name, fb->base.id);
    1070             : 
    1071             :                         /* should turn off the crtc */
    1072           0 :                         if (drm_crtc_force_disable(crtc))
    1073           0 :                                 DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
    1074             :                 }
    1075             :         }
    1076             : 
    1077           0 :         drm_for_each_plane(plane, dev) {
    1078           0 :                 if (plane->fb == fb) {
    1079           0 :                         drm_dbg_kms(dev,
    1080             :                                     "Disabling [PLANE:%d:%s] because [FB:%d] is removed\n",
    1081             :                                     plane->base.id, plane->name, fb->base.id);
    1082           0 :                         drm_plane_force_disable(plane);
    1083             :                 }
    1084             :         }
    1085           0 :         drm_modeset_unlock_all(dev);
    1086           0 : }
    1087             : 
    1088             : /**
    1089             :  * drm_framebuffer_remove - remove and unreference a framebuffer object
    1090             :  * @fb: framebuffer to remove
    1091             :  *
    1092             :  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
    1093             :  * using @fb, removes it, setting it to NULL. Then drops the reference to the
    1094             :  * passed-in framebuffer. Might take the modeset locks.
    1095             :  *
    1096             :  * Note that this function optimizes the cleanup away if the caller holds the
    1097             :  * last reference to the framebuffer. It is also guaranteed to not take the
    1098             :  * modeset locks in this case.
    1099             :  */
    1100           0 : void drm_framebuffer_remove(struct drm_framebuffer *fb)
    1101             : {
    1102             :         struct drm_device *dev;
    1103             : 
    1104           0 :         if (!fb)
    1105             :                 return;
    1106             : 
    1107           0 :         dev = fb->dev;
    1108             : 
    1109           0 :         WARN_ON(!list_empty(&fb->filp_head));
    1110             : 
    1111             :         /*
    1112             :          * drm ABI mandates that we remove any deleted framebuffers from active
    1113             :          * usage. But since most sane clients only remove framebuffers they no
    1114             :          * longer need, try to optimize this away.
    1115             :          *
    1116             :          * Since we're holding a reference ourselves, observing a refcount of 1
    1117             :          * means that we're the last holder and can skip it. Also, the refcount
    1118             :          * can never increase from 1 again, so we don't need any barriers or
    1119             :          * locks.
    1120             :          *
    1121             :          * Note that userspace could try to race with use and instate a new
    1122             :          * usage _after_ we've cleared all current ones. End result will be an
    1123             :          * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
    1124             :          * in this manner.
    1125             :          */
    1126           0 :         if (drm_framebuffer_read_refcount(fb) > 1) {
    1127           0 :                 if (drm_drv_uses_atomic_modeset(dev)) {
    1128           0 :                         int ret = atomic_remove_fb(fb);
    1129             : 
    1130           0 :                         WARN(ret, "atomic remove_fb failed with %i\n", ret);
    1131             :                 } else
    1132           0 :                         legacy_remove_fb(fb);
    1133             :         }
    1134             : 
    1135             :         drm_framebuffer_put(fb);
    1136             : }
    1137             : EXPORT_SYMBOL(drm_framebuffer_remove);
    1138             : 
    1139             : /**
    1140             :  * drm_framebuffer_plane_width - width of the plane given the first plane
    1141             :  * @width: width of the first plane
    1142             :  * @fb: the framebuffer
    1143             :  * @plane: plane index
    1144             :  *
    1145             :  * Returns:
    1146             :  * The width of @plane, given that the width of the first plane is @width.
    1147             :  */
    1148           0 : int drm_framebuffer_plane_width(int width,
    1149             :                                 const struct drm_framebuffer *fb, int plane)
    1150             : {
    1151           0 :         if (plane >= fb->format->num_planes)
    1152             :                 return 0;
    1153             : 
    1154           0 :         return fb_plane_width(width, fb->format, plane);
    1155             : }
    1156             : EXPORT_SYMBOL(drm_framebuffer_plane_width);
    1157             : 
    1158             : /**
    1159             :  * drm_framebuffer_plane_height - height of the plane given the first plane
    1160             :  * @height: height of the first plane
    1161             :  * @fb: the framebuffer
    1162             :  * @plane: plane index
    1163             :  *
    1164             :  * Returns:
    1165             :  * The height of @plane, given that the height of the first plane is @height.
    1166             :  */
    1167           0 : int drm_framebuffer_plane_height(int height,
    1168             :                                  const struct drm_framebuffer *fb, int plane)
    1169             : {
    1170           0 :         if (plane >= fb->format->num_planes)
    1171             :                 return 0;
    1172             : 
    1173           0 :         return fb_plane_height(height, fb->format, plane);
    1174             : }
    1175             : EXPORT_SYMBOL(drm_framebuffer_plane_height);
    1176             : 
    1177           0 : void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
    1178             :                                 const struct drm_framebuffer *fb)
    1179             : {
    1180             :         unsigned int i;
    1181             : 
    1182           0 :         drm_printf_indent(p, indent, "allocated by = %s\n", fb->comm);
    1183           0 :         drm_printf_indent(p, indent, "refcount=%u\n",
    1184             :                           drm_framebuffer_read_refcount(fb));
    1185           0 :         drm_printf_indent(p, indent, "format=%p4cc\n", &fb->format->format);
    1186           0 :         drm_printf_indent(p, indent, "modifier=0x%llx\n", fb->modifier);
    1187           0 :         drm_printf_indent(p, indent, "size=%ux%u\n", fb->width, fb->height);
    1188           0 :         drm_printf_indent(p, indent, "layers:\n");
    1189             : 
    1190           0 :         for (i = 0; i < fb->format->num_planes; i++) {
    1191           0 :                 drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i,
    1192             :                                   drm_framebuffer_plane_width(fb->width, fb, i),
    1193             :                                   drm_framebuffer_plane_height(fb->height, fb, i));
    1194           0 :                 drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]);
    1195           0 :                 drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]);
    1196           0 :                 drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i,
    1197             :                                   fb->obj[i] ? "" : "(null)");
    1198           0 :                 if (fb->obj[i])
    1199           0 :                         drm_gem_print_info(p, indent + 2, fb->obj[i]);
    1200             :         }
    1201           0 : }
    1202             : 
    1203             : #ifdef CONFIG_DEBUG_FS
    1204             : static int drm_framebuffer_info(struct seq_file *m, void *data)
    1205             : {
    1206             :         struct drm_debugfs_entry *entry = m->private;
    1207             :         struct drm_device *dev = entry->dev;
    1208             :         struct drm_printer p = drm_seq_file_printer(m);
    1209             :         struct drm_framebuffer *fb;
    1210             : 
    1211             :         mutex_lock(&dev->mode_config.fb_lock);
    1212             :         drm_for_each_fb(fb, dev) {
    1213             :                 drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
    1214             :                 drm_framebuffer_print_info(&p, 1, fb);
    1215             :         }
    1216             :         mutex_unlock(&dev->mode_config.fb_lock);
    1217             : 
    1218             :         return 0;
    1219             : }
    1220             : 
    1221             : static const struct drm_debugfs_info drm_framebuffer_debugfs_list[] = {
    1222             :         { "framebuffer", drm_framebuffer_info, 0 },
    1223             : };
    1224             : 
    1225             : void drm_framebuffer_debugfs_init(struct drm_minor *minor)
    1226             : {
    1227             :         drm_debugfs_add_files(minor->dev, drm_framebuffer_debugfs_list,
    1228             :                               ARRAY_SIZE(drm_framebuffer_debugfs_list));
    1229             : }
    1230             : #endif

Generated by: LCOV version 1.14