linux/drivers/gpu/drm/drm_plane.c
<<
>>
Prefs
   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 <drm/drmP.h>
  24#include <drm/drm_plane.h>
  25
  26#include "drm_crtc_internal.h"
  27
  28/**
  29 * DOC: overview
  30 *
  31 * A plane represents an image source that can be blended with or overlayed on
  32 * top of a CRTC during the scanout process. Planes take their input data from a
  33 * &drm_framebuffer object. The plane itself specifies the cropping and scaling
  34 * of that image, and where it is placed on the visible are of a display
  35 * pipeline, represented by &drm_crtc. A plane can also have additional
  36 * properties that specify how the pixels are positioned and blended, like
  37 * rotation or Z-position. All these properties are stored in &drm_plane_state.
  38 *
  39 * To create a plane, a KMS drivers allocates and zeroes an instances of
  40 * &struct drm_plane (possibly as part of a larger structure) and registers it
  41 * with a call to drm_universal_plane_init().
  42 *
  43 * Cursor and overlay planes are optional. All drivers should provide one
  44 * primary plane per CRTC to avoid surprising userspace too much. See enum
  45 * drm_plane_type for a more in-depth discussion of these special uapi-relevant
  46 * plane types. Special planes are associated with their CRTC by calling
  47 * drm_crtc_init_with_planes().
  48 *
  49 * The type of a plane is exposed in the immutable "type" enumeration property,
  50 * which has one of the following values: "Overlay", "Primary", "Cursor".
  51 */
  52
  53static unsigned int drm_num_planes(struct drm_device *dev)
  54{
  55        unsigned int num = 0;
  56        struct drm_plane *tmp;
  57
  58        drm_for_each_plane(tmp, dev) {
  59                num++;
  60        }
  61
  62        return num;
  63}
  64
  65/**
  66 * drm_universal_plane_init - Initialize a new universal plane object
  67 * @dev: DRM device
  68 * @plane: plane object to init
  69 * @possible_crtcs: bitmask of possible CRTCs
  70 * @funcs: callbacks for the new plane
  71 * @formats: array of supported formats (DRM_FORMAT\_\*)
  72 * @format_count: number of elements in @formats
  73 * @type: type of plane (overlay, primary, cursor)
  74 * @name: printf style format string for the plane name, or NULL for default name
  75 *
  76 * Initializes a plane object of type @type.
  77 *
  78 * Returns:
  79 * Zero on success, error code on failure.
  80 */
  81int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
  82                             uint32_t possible_crtcs,
  83                             const struct drm_plane_funcs *funcs,
  84                             const uint32_t *formats, unsigned int format_count,
  85                             enum drm_plane_type type,
  86                             const char *name, ...)
  87{
  88        struct drm_mode_config *config = &dev->mode_config;
  89        int ret;
  90
  91        ret = drm_mode_object_add(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
  92        if (ret)
  93                return ret;
  94
  95        drm_modeset_lock_init(&plane->mutex);
  96
  97        plane->base.properties = &plane->properties;
  98        plane->dev = dev;
  99        plane->funcs = funcs;
 100        plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
 101                                            GFP_KERNEL);
 102        if (!plane->format_types) {
 103                DRM_DEBUG_KMS("out of memory when allocating plane\n");
 104                drm_mode_object_unregister(dev, &plane->base);
 105                return -ENOMEM;
 106        }
 107
 108        if (name) {
 109                va_list ap;
 110
 111                va_start(ap, name);
 112                plane->name = kvasprintf(GFP_KERNEL, name, ap);
 113                va_end(ap);
 114        } else {
 115                plane->name = kasprintf(GFP_KERNEL, "plane-%d",
 116                                        drm_num_planes(dev));
 117        }
 118        if (!plane->name) {
 119                kfree(plane->format_types);
 120                drm_mode_object_unregister(dev, &plane->base);
 121                return -ENOMEM;
 122        }
 123
 124        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
 125        plane->format_count = format_count;
 126        plane->possible_crtcs = possible_crtcs;
 127        plane->type = type;
 128
 129        list_add_tail(&plane->head, &config->plane_list);
 130        plane->index = config->num_total_plane++;
 131        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 132                config->num_overlay_plane++;
 133
 134        drm_object_attach_property(&plane->base,
 135                                   config->plane_type_property,
 136                                   plane->type);
 137
 138        if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
 139                drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
 140                drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1);
 141                drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
 142                drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
 143                drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
 144                drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
 145                drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
 146                drm_object_attach_property(&plane->base, config->prop_src_x, 0);
 147                drm_object_attach_property(&plane->base, config->prop_src_y, 0);
 148                drm_object_attach_property(&plane->base, config->prop_src_w, 0);
 149                drm_object_attach_property(&plane->base, config->prop_src_h, 0);
 150        }
 151
 152        return 0;
 153}
 154EXPORT_SYMBOL(drm_universal_plane_init);
 155
 156int drm_plane_register_all(struct drm_device *dev)
 157{
 158        struct drm_plane *plane;
 159        int ret = 0;
 160
 161        drm_for_each_plane(plane, dev) {
 162                if (plane->funcs->late_register)
 163                        ret = plane->funcs->late_register(plane);
 164                if (ret)
 165                        return ret;
 166        }
 167
 168        return 0;
 169}
 170
 171void drm_plane_unregister_all(struct drm_device *dev)
 172{
 173        struct drm_plane *plane;
 174
 175        drm_for_each_plane(plane, dev) {
 176                if (plane->funcs->early_unregister)
 177                        plane->funcs->early_unregister(plane);
 178        }
 179}
 180
 181/**
 182 * drm_plane_init - Initialize a legacy plane
 183 * @dev: DRM device
 184 * @plane: plane object to init
 185 * @possible_crtcs: bitmask of possible CRTCs
 186 * @funcs: callbacks for the new plane
 187 * @formats: array of supported formats (DRM_FORMAT\_\*)
 188 * @format_count: number of elements in @formats
 189 * @is_primary: plane type (primary vs overlay)
 190 *
 191 * Legacy API to initialize a DRM plane.
 192 *
 193 * New drivers should call drm_universal_plane_init() instead.
 194 *
 195 * Returns:
 196 * Zero on success, error code on failure.
 197 */
 198int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 199                   uint32_t possible_crtcs,
 200                   const struct drm_plane_funcs *funcs,
 201                   const uint32_t *formats, unsigned int format_count,
 202                   bool is_primary)
 203{
 204        enum drm_plane_type type;
 205
 206        type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
 207        return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
 208                                        formats, format_count, type, NULL);
 209}
 210EXPORT_SYMBOL(drm_plane_init);
 211
 212/**
 213 * drm_plane_cleanup - Clean up the core plane usage
 214 * @plane: plane to cleanup
 215 *
 216 * This function cleans up @plane and removes it from the DRM mode setting
 217 * core. Note that the function does *not* free the plane structure itself,
 218 * this is the responsibility of the caller.
 219 */
 220void drm_plane_cleanup(struct drm_plane *plane)
 221{
 222        struct drm_device *dev = plane->dev;
 223
 224        drm_modeset_lock_fini(&plane->mutex);
 225
 226        kfree(plane->format_types);
 227        drm_mode_object_unregister(dev, &plane->base);
 228
 229        BUG_ON(list_empty(&plane->head));
 230
 231        /* Note that the plane_list is considered to be static; should we
 232         * remove the drm_plane at runtime we would have to decrement all
 233         * the indices on the drm_plane after us in the plane_list.
 234         */
 235
 236        list_del(&plane->head);
 237        dev->mode_config.num_total_plane--;
 238        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
 239                dev->mode_config.num_overlay_plane--;
 240
 241        WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
 242        if (plane->state && plane->funcs->atomic_destroy_state)
 243                plane->funcs->atomic_destroy_state(plane, plane->state);
 244
 245        kfree(plane->name);
 246
 247        memset(plane, 0, sizeof(*plane));
 248}
 249EXPORT_SYMBOL(drm_plane_cleanup);
 250
 251/**
 252 * drm_plane_from_index - find the registered plane at an index
 253 * @dev: DRM device
 254 * @idx: index of registered plane to find for
 255 *
 256 * Given a plane index, return the registered plane from DRM device's
 257 * list of planes with matching index. This is the inverse of drm_plane_index().
 258 */
 259struct drm_plane *
 260drm_plane_from_index(struct drm_device *dev, int idx)
 261{
 262        struct drm_plane *plane;
 263
 264        drm_for_each_plane(plane, dev)
 265                if (idx == plane->index)
 266                        return plane;
 267
 268        return NULL;
 269}
 270EXPORT_SYMBOL(drm_plane_from_index);
 271
 272/**
 273 * drm_plane_force_disable - Forcibly disable a plane
 274 * @plane: plane to disable
 275 *
 276 * Forces the plane to be disabled.
 277 *
 278 * Used when the plane's current framebuffer is destroyed,
 279 * and when restoring fbdev mode.
 280 *
 281 * Note that this function is not suitable for atomic drivers, since it doesn't
 282 * wire through the lock acquisition context properly and hence can't handle
 283 * retries or driver private locks. You probably want to use
 284 * drm_atomic_helper_disable_plane() or
 285 * drm_atomic_helper_disable_planes_on_crtc() instead.
 286 */
 287void drm_plane_force_disable(struct drm_plane *plane)
 288{
 289        int ret;
 290
 291        if (!plane->fb)
 292                return;
 293
 294        WARN_ON(drm_drv_uses_atomic_modeset(plane->dev));
 295
 296        plane->old_fb = plane->fb;
 297        ret = plane->funcs->disable_plane(plane, NULL);
 298        if (ret) {
 299                DRM_ERROR("failed to disable plane with busy fb\n");
 300                plane->old_fb = NULL;
 301                return;
 302        }
 303        /* disconnect the plane from the fb and crtc: */
 304        drm_framebuffer_put(plane->old_fb);
 305        plane->old_fb = NULL;
 306        plane->fb = NULL;
 307        plane->crtc = NULL;
 308}
 309EXPORT_SYMBOL(drm_plane_force_disable);
 310
 311/**
 312 * drm_mode_plane_set_obj_prop - set the value of a property
 313 * @plane: drm plane object to set property value for
 314 * @property: property to set
 315 * @value: value the property should be set to
 316 *
 317 * This functions sets a given property on a given plane object. This function
 318 * calls the driver's ->set_property callback and changes the software state of
 319 * the property if the callback succeeds.
 320 *
 321 * Returns:
 322 * Zero on success, error code on failure.
 323 */
 324int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 325                                struct drm_property *property,
 326                                uint64_t value)
 327{
 328        int ret = -EINVAL;
 329        struct drm_mode_object *obj = &plane->base;
 330
 331        if (plane->funcs->set_property)
 332                ret = plane->funcs->set_property(plane, property, value);
 333        if (!ret)
 334                drm_object_property_set_value(obj, property, value);
 335
 336        return ret;
 337}
 338EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 339
 340int drm_mode_getplane_res(struct drm_device *dev, void *data,
 341                          struct drm_file *file_priv)
 342{
 343        struct drm_mode_get_plane_res *plane_resp = data;
 344        struct drm_mode_config *config;
 345        struct drm_plane *plane;
 346        uint32_t __user *plane_ptr;
 347        int copied = 0;
 348        unsigned num_planes;
 349
 350        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 351                return -EINVAL;
 352
 353        config = &dev->mode_config;
 354
 355        if (file_priv->universal_planes)
 356                num_planes = config->num_total_plane;
 357        else
 358                num_planes = config->num_overlay_plane;
 359
 360        /*
 361         * This ioctl is called twice, once to determine how much space is
 362         * needed, and the 2nd time to fill it.
 363         */
 364        if (num_planes &&
 365            (plane_resp->count_planes >= num_planes)) {
 366                plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 367
 368                /* Plane lists are invariant, no locking needed. */
 369                drm_for_each_plane(plane, dev) {
 370                        /*
 371                         * Unless userspace set the 'universal planes'
 372                         * capability bit, only advertise overlays.
 373                         */
 374                        if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
 375                            !file_priv->universal_planes)
 376                                continue;
 377
 378                        if (put_user(plane->base.id, plane_ptr + copied))
 379                                return -EFAULT;
 380                        copied++;
 381                }
 382        }
 383        plane_resp->count_planes = num_planes;
 384
 385        return 0;
 386}
 387
 388int drm_mode_getplane(struct drm_device *dev, void *data,
 389                      struct drm_file *file_priv)
 390{
 391        struct drm_mode_get_plane *plane_resp = data;
 392        struct drm_plane *plane;
 393        uint32_t __user *format_ptr;
 394
 395        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 396                return -EINVAL;
 397
 398        plane = drm_plane_find(dev, plane_resp->plane_id);
 399        if (!plane)
 400                return -ENOENT;
 401
 402        drm_modeset_lock(&plane->mutex, NULL);
 403        if (plane->state && plane->state->crtc)
 404                plane_resp->crtc_id = plane->state->crtc->base.id;
 405        else if (!plane->state && plane->crtc)
 406                plane_resp->crtc_id = plane->crtc->base.id;
 407        else
 408                plane_resp->crtc_id = 0;
 409
 410        if (plane->state && plane->state->fb)
 411                plane_resp->fb_id = plane->state->fb->base.id;
 412        else if (!plane->state && plane->fb)
 413                plane_resp->fb_id = plane->fb->base.id;
 414        else
 415                plane_resp->fb_id = 0;
 416        drm_modeset_unlock(&plane->mutex);
 417
 418        plane_resp->plane_id = plane->base.id;
 419        plane_resp->possible_crtcs = plane->possible_crtcs;
 420        plane_resp->gamma_size = 0;
 421
 422        /*
 423         * This ioctl is called twice, once to determine how much space is
 424         * needed, and the 2nd time to fill it.
 425         */
 426        if (plane->format_count &&
 427            (plane_resp->count_format_types >= plane->format_count)) {
 428                format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
 429                if (copy_to_user(format_ptr,
 430                                 plane->format_types,
 431                                 sizeof(uint32_t) * plane->format_count)) {
 432                        return -EFAULT;
 433                }
 434        }
 435        plane_resp->count_format_types = plane->format_count;
 436
 437        return 0;
 438}
 439
 440int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
 441{
 442        unsigned int i;
 443
 444        for (i = 0; i < plane->format_count; i++) {
 445                if (format == plane->format_types[i])
 446                        return 0;
 447        }
 448
 449        return -EINVAL;
 450}
 451
 452/*
 453 * setplane_internal - setplane handler for internal callers
 454 *
 455 * Note that we assume an extra reference has already been taken on fb.  If the
 456 * update fails, this reference will be dropped before return; if it succeeds,
 457 * the previous framebuffer (if any) will be unreferenced instead.
 458 *
 459 * src_{x,y,w,h} are provided in 16.16 fixed point format
 460 */
 461static int __setplane_internal(struct drm_plane *plane,
 462                               struct drm_crtc *crtc,
 463                               struct drm_framebuffer *fb,
 464                               int32_t crtc_x, int32_t crtc_y,
 465                               uint32_t crtc_w, uint32_t crtc_h,
 466                               /* src_{x,y,w,h} values are 16.16 fixed point */
 467                               uint32_t src_x, uint32_t src_y,
 468                               uint32_t src_w, uint32_t src_h,
 469                               struct drm_modeset_acquire_ctx *ctx)
 470{
 471        int ret = 0;
 472
 473        /* No fb means shut it down */
 474        if (!fb) {
 475                plane->old_fb = plane->fb;
 476                ret = plane->funcs->disable_plane(plane, ctx);
 477                if (!ret) {
 478                        plane->crtc = NULL;
 479                        plane->fb = NULL;
 480                } else {
 481                        plane->old_fb = NULL;
 482                }
 483                goto out;
 484        }
 485
 486        /* Check whether this plane is usable on this CRTC */
 487        if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) {
 488                DRM_DEBUG_KMS("Invalid crtc for plane\n");
 489                ret = -EINVAL;
 490                goto out;
 491        }
 492
 493        /* Check whether this plane supports the fb pixel format. */
 494        ret = drm_plane_check_pixel_format(plane, fb->format->format);
 495        if (ret) {
 496                struct drm_format_name_buf format_name;
 497                DRM_DEBUG_KMS("Invalid pixel format %s\n",
 498                              drm_get_format_name(fb->format->format,
 499                                                  &format_name));
 500                goto out;
 501        }
 502
 503        /* Give drivers some help against integer overflows */
 504        if (crtc_w > INT_MAX ||
 505            crtc_x > INT_MAX - (int32_t) crtc_w ||
 506            crtc_h > INT_MAX ||
 507            crtc_y > INT_MAX - (int32_t) crtc_h) {
 508                DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
 509                              crtc_w, crtc_h, crtc_x, crtc_y);
 510                ret = -ERANGE;
 511                goto out;
 512        }
 513
 514        ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb);
 515        if (ret)
 516                goto out;
 517
 518        plane->old_fb = plane->fb;
 519        ret = plane->funcs->update_plane(plane, crtc, fb,
 520                                         crtc_x, crtc_y, crtc_w, crtc_h,
 521                                         src_x, src_y, src_w, src_h, ctx);
 522        if (!ret) {
 523                plane->crtc = crtc;
 524                plane->fb = fb;
 525                fb = NULL;
 526        } else {
 527                plane->old_fb = NULL;
 528        }
 529
 530out:
 531        if (fb)
 532                drm_framebuffer_put(fb);
 533        if (plane->old_fb)
 534                drm_framebuffer_put(plane->old_fb);
 535        plane->old_fb = NULL;
 536
 537        return ret;
 538}
 539
 540static int setplane_internal(struct drm_plane *plane,
 541                             struct drm_crtc *crtc,
 542                             struct drm_framebuffer *fb,
 543                             int32_t crtc_x, int32_t crtc_y,
 544                             uint32_t crtc_w, uint32_t crtc_h,
 545                             /* src_{x,y,w,h} values are 16.16 fixed point */
 546                             uint32_t src_x, uint32_t src_y,
 547                             uint32_t src_w, uint32_t src_h)
 548{
 549        struct drm_modeset_acquire_ctx ctx;
 550        int ret;
 551
 552        drm_modeset_acquire_init(&ctx, 0);
 553retry:
 554        ret = drm_modeset_lock_all_ctx(plane->dev, &ctx);
 555        if (ret)
 556                goto fail;
 557        ret = __setplane_internal(plane, crtc, fb,
 558                                  crtc_x, crtc_y, crtc_w, crtc_h,
 559                                  src_x, src_y, src_w, src_h, &ctx);
 560
 561fail:
 562        if (ret == -EDEADLK) {
 563                drm_modeset_backoff(&ctx);
 564                goto retry;
 565        }
 566        drm_modeset_drop_locks(&ctx);
 567        drm_modeset_acquire_fini(&ctx);
 568
 569        return ret;
 570}
 571
 572int drm_mode_setplane(struct drm_device *dev, void *data,
 573                      struct drm_file *file_priv)
 574{
 575        struct drm_mode_set_plane *plane_req = data;
 576        struct drm_plane *plane;
 577        struct drm_crtc *crtc = NULL;
 578        struct drm_framebuffer *fb = NULL;
 579
 580        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 581                return -EINVAL;
 582
 583        /*
 584         * First, find the plane, crtc, and fb objects.  If not available,
 585         * we don't bother to call the driver.
 586         */
 587        plane = drm_plane_find(dev, plane_req->plane_id);
 588        if (!plane) {
 589                DRM_DEBUG_KMS("Unknown plane ID %d\n",
 590                              plane_req->plane_id);
 591                return -ENOENT;
 592        }
 593
 594        if (plane_req->fb_id) {
 595                fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
 596                if (!fb) {
 597                        DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
 598                                      plane_req->fb_id);
 599                        return -ENOENT;
 600                }
 601
 602                crtc = drm_crtc_find(dev, plane_req->crtc_id);
 603                if (!crtc) {
 604                        drm_framebuffer_put(fb);
 605                        DRM_DEBUG_KMS("Unknown crtc ID %d\n",
 606                                      plane_req->crtc_id);
 607                        return -ENOENT;
 608                }
 609        }
 610
 611        /*
 612         * setplane_internal will take care of deref'ing either the old or new
 613         * framebuffer depending on success.
 614         */
 615        return setplane_internal(plane, crtc, fb,
 616                                 plane_req->crtc_x, plane_req->crtc_y,
 617                                 plane_req->crtc_w, plane_req->crtc_h,
 618                                 plane_req->src_x, plane_req->src_y,
 619                                 plane_req->src_w, plane_req->src_h);
 620}
 621
 622static int drm_mode_cursor_universal(struct drm_crtc *crtc,
 623                                     struct drm_mode_cursor2 *req,
 624                                     struct drm_file *file_priv,
 625                                     struct drm_modeset_acquire_ctx *ctx)
 626{
 627        struct drm_device *dev = crtc->dev;
 628        struct drm_framebuffer *fb = NULL;
 629        struct drm_mode_fb_cmd2 fbreq = {
 630                .width = req->width,
 631                .height = req->height,
 632                .pixel_format = DRM_FORMAT_ARGB8888,
 633                .pitches = { req->width * 4 },
 634                .handles = { req->handle },
 635        };
 636        int32_t crtc_x, crtc_y;
 637        uint32_t crtc_w = 0, crtc_h = 0;
 638        uint32_t src_w = 0, src_h = 0;
 639        int ret = 0;
 640
 641        BUG_ON(!crtc->cursor);
 642        WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
 643
 644        /*
 645         * Obtain fb we'll be using (either new or existing) and take an extra
 646         * reference to it if fb != null.  setplane will take care of dropping
 647         * the reference if the plane update fails.
 648         */
 649        if (req->flags & DRM_MODE_CURSOR_BO) {
 650                if (req->handle) {
 651                        fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv);
 652                        if (IS_ERR(fb)) {
 653                                DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n");
 654                                return PTR_ERR(fb);
 655                        }
 656                        fb->hot_x = req->hot_x;
 657                        fb->hot_y = req->hot_y;
 658                } else {
 659                        fb = NULL;
 660                }
 661        } else {
 662                fb = crtc->cursor->fb;
 663                if (fb)
 664                        drm_framebuffer_get(fb);
 665        }
 666
 667        if (req->flags & DRM_MODE_CURSOR_MOVE) {
 668                crtc_x = req->x;
 669                crtc_y = req->y;
 670        } else {
 671                crtc_x = crtc->cursor_x;
 672                crtc_y = crtc->cursor_y;
 673        }
 674
 675        if (fb) {
 676                crtc_w = fb->width;
 677                crtc_h = fb->height;
 678                src_w = fb->width << 16;
 679                src_h = fb->height << 16;
 680        }
 681
 682        /*
 683         * setplane_internal will take care of deref'ing either the old or new
 684         * framebuffer depending on success.
 685         */
 686        ret = __setplane_internal(crtc->cursor, crtc, fb,
 687                                crtc_x, crtc_y, crtc_w, crtc_h,
 688                                0, 0, src_w, src_h, ctx);
 689
 690        /* Update successful; save new cursor position, if necessary */
 691        if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
 692                crtc->cursor_x = req->x;
 693                crtc->cursor_y = req->y;
 694        }
 695
 696        return ret;
 697}
 698
 699static int drm_mode_cursor_common(struct drm_device *dev,
 700                                  struct drm_mode_cursor2 *req,
 701                                  struct drm_file *file_priv)
 702{
 703        struct drm_crtc *crtc;
 704        struct drm_modeset_acquire_ctx ctx;
 705        int ret = 0;
 706
 707        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 708                return -EINVAL;
 709
 710        if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 711                return -EINVAL;
 712
 713        crtc = drm_crtc_find(dev, req->crtc_id);
 714        if (!crtc) {
 715                DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
 716                return -ENOENT;
 717        }
 718
 719        drm_modeset_acquire_init(&ctx, 0);
 720retry:
 721        ret = drm_modeset_lock(&crtc->mutex, &ctx);
 722        if (ret)
 723                goto out;
 724        /*
 725         * If this crtc has a universal cursor plane, call that plane's update
 726         * handler rather than using legacy cursor handlers.
 727         */
 728        if (crtc->cursor) {
 729                ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx);
 730                if (ret)
 731                        goto out;
 732
 733                ret = drm_mode_cursor_universal(crtc, req, file_priv, &ctx);
 734                goto out;
 735        }
 736
 737        if (req->flags & DRM_MODE_CURSOR_BO) {
 738                if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
 739                        ret = -ENXIO;
 740                        goto out;
 741                }
 742                /* Turns off the cursor if handle is 0 */
 743                if (crtc->funcs->cursor_set2)
 744                        ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
 745                                                      req->width, req->height, req->hot_x, req->hot_y);
 746                else
 747                        ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
 748                                                      req->width, req->height);
 749        }
 750
 751        if (req->flags & DRM_MODE_CURSOR_MOVE) {
 752                if (crtc->funcs->cursor_move) {
 753                        ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
 754                } else {
 755                        ret = -EFAULT;
 756                        goto out;
 757                }
 758        }
 759out:
 760        if (ret == -EDEADLK) {
 761                drm_modeset_backoff(&ctx);
 762                goto retry;
 763        }
 764
 765        drm_modeset_drop_locks(&ctx);
 766        drm_modeset_acquire_fini(&ctx);
 767
 768        return ret;
 769
 770}
 771
 772
 773int drm_mode_cursor_ioctl(struct drm_device *dev,
 774                          void *data, struct drm_file *file_priv)
 775{
 776        struct drm_mode_cursor *req = data;
 777        struct drm_mode_cursor2 new_req;
 778
 779        memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
 780        new_req.hot_x = new_req.hot_y = 0;
 781
 782        return drm_mode_cursor_common(dev, &new_req, file_priv);
 783}
 784
 785/*
 786 * Set the cursor configuration based on user request. This implements the 2nd
 787 * version of the cursor ioctl, which allows userspace to additionally specify
 788 * the hotspot of the pointer.
 789 */
 790int drm_mode_cursor2_ioctl(struct drm_device *dev,
 791                           void *data, struct drm_file *file_priv)
 792{
 793        struct drm_mode_cursor2 *req = data;
 794
 795        return drm_mode_cursor_common(dev, req, file_priv);
 796}
 797
 798int drm_mode_page_flip_ioctl(struct drm_device *dev,
 799                             void *data, struct drm_file *file_priv)
 800{
 801        struct drm_mode_crtc_page_flip_target *page_flip = data;
 802        struct drm_crtc *crtc;
 803        struct drm_framebuffer *fb = NULL;
 804        struct drm_pending_vblank_event *e = NULL;
 805        u32 target_vblank = page_flip->sequence;
 806        struct drm_modeset_acquire_ctx ctx;
 807        int ret = -EINVAL;
 808
 809        if (!drm_core_check_feature(dev, DRIVER_MODESET))
 810                return -EINVAL;
 811
 812        if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
 813                return -EINVAL;
 814
 815        if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
 816                return -EINVAL;
 817
 818        /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
 819         * can be specified
 820         */
 821        if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
 822                return -EINVAL;
 823
 824        if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
 825                return -EINVAL;
 826
 827        crtc = drm_crtc_find(dev, page_flip->crtc_id);
 828        if (!crtc)
 829                return -ENOENT;
 830
 831        if (crtc->funcs->page_flip_target) {
 832                u32 current_vblank;
 833                int r;
 834
 835                r = drm_crtc_vblank_get(crtc);
 836                if (r)
 837                        return r;
 838
 839                current_vblank = drm_crtc_vblank_count(crtc);
 840
 841                switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
 842                case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
 843                        if ((int)(target_vblank - current_vblank) > 1) {
 844                                DRM_DEBUG("Invalid absolute flip target %u, "
 845                                          "must be <= %u\n", target_vblank,
 846                                          current_vblank + 1);
 847                                drm_crtc_vblank_put(crtc);
 848                                return -EINVAL;
 849                        }
 850                        break;
 851                case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
 852                        if (target_vblank != 0 && target_vblank != 1) {
 853                                DRM_DEBUG("Invalid relative flip target %u, "
 854                                          "must be 0 or 1\n", target_vblank);
 855                                drm_crtc_vblank_put(crtc);
 856                                return -EINVAL;
 857                        }
 858                        target_vblank += current_vblank;
 859                        break;
 860                default:
 861                        target_vblank = current_vblank +
 862                                !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
 863                        break;
 864                }
 865        } else if (crtc->funcs->page_flip == NULL ||
 866                   (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
 867                return -EINVAL;
 868        }
 869
 870        drm_modeset_acquire_init(&ctx, 0);
 871retry:
 872        ret = drm_modeset_lock(&crtc->mutex, &ctx);
 873        if (ret)
 874                goto out;
 875        ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
 876        if (ret)
 877                goto out;
 878
 879        if (crtc->primary->fb == NULL) {
 880                /* The framebuffer is currently unbound, presumably
 881                 * due to a hotplug event, that userspace has not
 882                 * yet discovered.
 883                 */
 884                ret = -EBUSY;
 885                goto out;
 886        }
 887
 888        fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
 889        if (!fb) {
 890                ret = -ENOENT;
 891                goto out;
 892        }
 893
 894        if (crtc->state) {
 895                const struct drm_plane_state *state = crtc->primary->state;
 896
 897                ret = drm_framebuffer_check_src_coords(state->src_x,
 898                                                       state->src_y,
 899                                                       state->src_w,
 900                                                       state->src_h,
 901                                                       fb);
 902        } else {
 903                ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
 904        }
 905        if (ret)
 906                goto out;
 907
 908        if (crtc->primary->fb->format != fb->format) {
 909                DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
 910                ret = -EINVAL;
 911                goto out;
 912        }
 913
 914        if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
 915                e = kzalloc(sizeof *e, GFP_KERNEL);
 916                if (!e) {
 917                        ret = -ENOMEM;
 918                        goto out;
 919                }
 920                e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
 921                e->event.base.length = sizeof(e->event);
 922                e->event.user_data = page_flip->user_data;
 923                ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
 924                if (ret) {
 925                        kfree(e);
 926                        e = NULL;
 927                        goto out;
 928                }
 929        }
 930
 931        crtc->primary->old_fb = crtc->primary->fb;
 932        if (crtc->funcs->page_flip_target)
 933                ret = crtc->funcs->page_flip_target(crtc, fb, e,
 934                                                    page_flip->flags,
 935                                                    target_vblank,
 936                                                    &ctx);
 937        else
 938                ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags,
 939                                             &ctx);
 940        if (ret) {
 941                if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
 942                        drm_event_cancel_free(dev, &e->base);
 943                /* Keep the old fb, don't unref it. */
 944                crtc->primary->old_fb = NULL;
 945        } else {
 946                crtc->primary->fb = fb;
 947                /* Unref only the old framebuffer. */
 948                fb = NULL;
 949        }
 950
 951out:
 952        if (fb)
 953                drm_framebuffer_put(fb);
 954        if (crtc->primary->old_fb)
 955                drm_framebuffer_put(crtc->primary->old_fb);
 956        crtc->primary->old_fb = NULL;
 957
 958        if (ret == -EDEADLK) {
 959                drm_modeset_backoff(&ctx);
 960                goto retry;
 961        }
 962
 963        drm_modeset_drop_locks(&ctx);
 964        drm_modeset_acquire_fini(&ctx);
 965
 966        if (ret && crtc->funcs->page_flip_target)
 967                drm_crtc_vblank_put(crtc);
 968
 969        return ret;
 970}
 971