diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-08-15 10:07:02 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-08-16 10:49:03 -0400 |
commit | 7520a277d97be6e8a8ec038bb5ed01f40d4f9aeb (patch) | |
tree | 23ef983aeb5fc94f9123043f3612eff0831bb862 /drivers/gpu/drm/drm_crtc.c | |
parent | 5d070be68380baf61279d650b52563243cfaaa00 (diff) |
drm: Extract drm_framebuffer.[hc]
Also start with drm_modeset.h with the core bits, since we need
to untangle this mess somehow. That allows us to move the drm_modes.h
include to the right spot, except for the temporary connector status
enum. That will get fixed as soon as drm_connector.h exists.
v2: Rebase.
v3: Move drm_crtc_force_disable_all back again, that wasn't meant to
be moved (Sean).
v4: Rebase.
Cc: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 801 |
1 files changed, 15 insertions, 786 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index eb7aba874652..d596a491b517 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -40,15 +40,11 @@ | |||
40 | #include <drm/drm_modeset_lock.h> | 40 | #include <drm/drm_modeset_lock.h> |
41 | #include <drm/drm_atomic.h> | 41 | #include <drm/drm_atomic.h> |
42 | #include <drm/drm_auth.h> | 42 | #include <drm/drm_auth.h> |
43 | #include <drm/drm_framebuffer.h> | ||
43 | 44 | ||
44 | #include "drm_crtc_internal.h" | 45 | #include "drm_crtc_internal.h" |
45 | #include "drm_internal.h" | 46 | #include "drm_internal.h" |
46 | 47 | ||
47 | static struct drm_framebuffer * | ||
48 | internal_framebuffer_create(struct drm_device *dev, | ||
49 | const struct drm_mode_fb_cmd2 *r, | ||
50 | struct drm_file *file_priv); | ||
51 | |||
52 | /* Avoid boilerplate. I'm tired of typing. */ | 48 | /* Avoid boilerplate. I'm tired of typing. */ |
53 | #define DRM_ENUM_NAME_FN(fnname, list) \ | 49 | #define DRM_ENUM_NAME_FN(fnname, list) \ |
54 | const char *fnname(int val) \ | 50 | const char *fnname(int val) \ |
@@ -238,11 +234,11 @@ EXPORT_SYMBOL(drm_get_subpixel_order_name); | |||
238 | * Internal function to assign a slot in the object idr and optionally | 234 | * Internal function to assign a slot in the object idr and optionally |
239 | * register the object into the idr. | 235 | * register the object into the idr. |
240 | */ | 236 | */ |
241 | static int drm_mode_object_get_reg(struct drm_device *dev, | 237 | int drm_mode_object_get_reg(struct drm_device *dev, |
242 | struct drm_mode_object *obj, | 238 | struct drm_mode_object *obj, |
243 | uint32_t obj_type, | 239 | uint32_t obj_type, |
244 | bool register_obj, | 240 | bool register_obj, |
245 | void (*obj_free_cb)(struct kref *kref)) | 241 | void (*obj_free_cb)(struct kref *kref)) |
246 | { | 242 | { |
247 | int ret; | 243 | int ret; |
248 | 244 | ||
@@ -285,8 +281,8 @@ int drm_mode_object_get(struct drm_device *dev, | |||
285 | return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); | 281 | return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL); |
286 | } | 282 | } |
287 | 283 | ||
288 | static void drm_mode_object_register(struct drm_device *dev, | 284 | void drm_mode_object_register(struct drm_device *dev, |
289 | struct drm_mode_object *obj) | 285 | struct drm_mode_object *obj) |
290 | { | 286 | { |
291 | mutex_lock(&dev->mode_config.idr_mutex); | 287 | mutex_lock(&dev->mode_config.idr_mutex); |
292 | idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); | 288 | idr_replace(&dev->mode_config.crtc_idr, obj, obj->id); |
@@ -315,8 +311,8 @@ void drm_mode_object_unregister(struct drm_device *dev, | |||
315 | mutex_unlock(&dev->mode_config.idr_mutex); | 311 | mutex_unlock(&dev->mode_config.idr_mutex); |
316 | } | 312 | } |
317 | 313 | ||
318 | static struct drm_mode_object *_object_find(struct drm_device *dev, | 314 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, |
319 | uint32_t id, uint32_t type) | 315 | uint32_t id, uint32_t type) |
320 | { | 316 | { |
321 | struct drm_mode_object *obj = NULL; | 317 | struct drm_mode_object *obj = NULL; |
322 | 318 | ||
@@ -351,7 +347,7 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | |||
351 | { | 347 | { |
352 | struct drm_mode_object *obj = NULL; | 348 | struct drm_mode_object *obj = NULL; |
353 | 349 | ||
354 | obj = _object_find(dev, id, type); | 350 | obj = __drm_mode_object_find(dev, id, type); |
355 | return obj; | 351 | return obj; |
356 | } | 352 | } |
357 | EXPORT_SYMBOL(drm_mode_object_find); | 353 | EXPORT_SYMBOL(drm_mode_object_find); |
@@ -435,199 +431,6 @@ out: | |||
435 | } | 431 | } |
436 | EXPORT_SYMBOL(drm_crtc_force_disable_all); | 432 | EXPORT_SYMBOL(drm_crtc_force_disable_all); |
437 | 433 | ||
438 | static void drm_framebuffer_free(struct kref *kref) | ||
439 | { | ||
440 | struct drm_framebuffer *fb = | ||
441 | container_of(kref, struct drm_framebuffer, base.refcount); | ||
442 | struct drm_device *dev = fb->dev; | ||
443 | |||
444 | /* | ||
445 | * The lookup idr holds a weak reference, which has not necessarily been | ||
446 | * removed at this point. Check for that. | ||
447 | */ | ||
448 | drm_mode_object_unregister(dev, &fb->base); | ||
449 | |||
450 | fb->funcs->destroy(fb); | ||
451 | } | ||
452 | |||
453 | /** | ||
454 | * drm_framebuffer_init - initialize a framebuffer | ||
455 | * @dev: DRM device | ||
456 | * @fb: framebuffer to be initialized | ||
457 | * @funcs: ... with these functions | ||
458 | * | ||
459 | * Allocates an ID for the framebuffer's parent mode object, sets its mode | ||
460 | * functions & device file and adds it to the master fd list. | ||
461 | * | ||
462 | * IMPORTANT: | ||
463 | * This functions publishes the fb and makes it available for concurrent access | ||
464 | * by other users. Which means by this point the fb _must_ be fully set up - | ||
465 | * since all the fb attributes are invariant over its lifetime, no further | ||
466 | * locking but only correct reference counting is required. | ||
467 | * | ||
468 | * Returns: | ||
469 | * Zero on success, error code on failure. | ||
470 | */ | ||
471 | int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | ||
472 | const struct drm_framebuffer_funcs *funcs) | ||
473 | { | ||
474 | int ret; | ||
475 | |||
476 | INIT_LIST_HEAD(&fb->filp_head); | ||
477 | fb->dev = dev; | ||
478 | fb->funcs = funcs; | ||
479 | |||
480 | ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, | ||
481 | false, drm_framebuffer_free); | ||
482 | if (ret) | ||
483 | goto out; | ||
484 | |||
485 | mutex_lock(&dev->mode_config.fb_lock); | ||
486 | dev->mode_config.num_fb++; | ||
487 | list_add(&fb->head, &dev->mode_config.fb_list); | ||
488 | mutex_unlock(&dev->mode_config.fb_lock); | ||
489 | |||
490 | drm_mode_object_register(dev, &fb->base); | ||
491 | out: | ||
492 | return ret; | ||
493 | } | ||
494 | EXPORT_SYMBOL(drm_framebuffer_init); | ||
495 | |||
496 | /** | ||
497 | * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference | ||
498 | * @dev: drm device | ||
499 | * @id: id of the fb object | ||
500 | * | ||
501 | * If successful, this grabs an additional reference to the framebuffer - | ||
502 | * callers need to make sure to eventually unreference the returned framebuffer | ||
503 | * again, using @drm_framebuffer_unreference. | ||
504 | */ | ||
505 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
506 | uint32_t id) | ||
507 | { | ||
508 | struct drm_mode_object *obj; | ||
509 | struct drm_framebuffer *fb = NULL; | ||
510 | |||
511 | obj = _object_find(dev, id, DRM_MODE_OBJECT_FB); | ||
512 | if (obj) | ||
513 | fb = obj_to_fb(obj); | ||
514 | return fb; | ||
515 | } | ||
516 | EXPORT_SYMBOL(drm_framebuffer_lookup); | ||
517 | |||
518 | /** | ||
519 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr | ||
520 | * @fb: fb to unregister | ||
521 | * | ||
522 | * Drivers need to call this when cleaning up driver-private framebuffers, e.g. | ||
523 | * those used for fbdev. Note that the caller must hold a reference of it's own, | ||
524 | * i.e. the object may not be destroyed through this call (since it'll lead to a | ||
525 | * locking inversion). | ||
526 | */ | ||
527 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) | ||
528 | { | ||
529 | struct drm_device *dev; | ||
530 | |||
531 | if (!fb) | ||
532 | return; | ||
533 | |||
534 | dev = fb->dev; | ||
535 | |||
536 | /* Mark fb as reaped and drop idr ref. */ | ||
537 | drm_mode_object_unregister(dev, &fb->base); | ||
538 | } | ||
539 | EXPORT_SYMBOL(drm_framebuffer_unregister_private); | ||
540 | |||
541 | /** | ||
542 | * drm_framebuffer_cleanup - remove a framebuffer object | ||
543 | * @fb: framebuffer to remove | ||
544 | * | ||
545 | * Cleanup framebuffer. This function is intended to be used from the drivers | ||
546 | * ->destroy callback. It can also be used to clean up driver private | ||
547 | * framebuffers embedded into a larger structure. | ||
548 | * | ||
549 | * Note that this function does not remove the fb from active usuage - if it is | ||
550 | * still used anywhere, hilarity can ensue since userspace could call getfb on | ||
551 | * the id and get back -EINVAL. Obviously no concern at driver unload time. | ||
552 | * | ||
553 | * Also, the framebuffer will not be removed from the lookup idr - for | ||
554 | * user-created framebuffers this will happen in in the rmfb ioctl. For | ||
555 | * driver-private objects (e.g. for fbdev) drivers need to explicitly call | ||
556 | * drm_framebuffer_unregister_private. | ||
557 | */ | ||
558 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | ||
559 | { | ||
560 | struct drm_device *dev = fb->dev; | ||
561 | |||
562 | mutex_lock(&dev->mode_config.fb_lock); | ||
563 | list_del(&fb->head); | ||
564 | dev->mode_config.num_fb--; | ||
565 | mutex_unlock(&dev->mode_config.fb_lock); | ||
566 | } | ||
567 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | ||
568 | |||
569 | /** | ||
570 | * drm_framebuffer_remove - remove and unreference a framebuffer object | ||
571 | * @fb: framebuffer to remove | ||
572 | * | ||
573 | * Scans all the CRTCs and planes in @dev's mode_config. If they're | ||
574 | * using @fb, removes it, setting it to NULL. Then drops the reference to the | ||
575 | * passed-in framebuffer. Might take the modeset locks. | ||
576 | * | ||
577 | * Note that this function optimizes the cleanup away if the caller holds the | ||
578 | * last reference to the framebuffer. It is also guaranteed to not take the | ||
579 | * modeset locks in this case. | ||
580 | */ | ||
581 | void drm_framebuffer_remove(struct drm_framebuffer *fb) | ||
582 | { | ||
583 | struct drm_device *dev; | ||
584 | struct drm_crtc *crtc; | ||
585 | struct drm_plane *plane; | ||
586 | |||
587 | if (!fb) | ||
588 | return; | ||
589 | |||
590 | dev = fb->dev; | ||
591 | |||
592 | WARN_ON(!list_empty(&fb->filp_head)); | ||
593 | |||
594 | /* | ||
595 | * drm ABI mandates that we remove any deleted framebuffers from active | ||
596 | * useage. But since most sane clients only remove framebuffers they no | ||
597 | * longer need, try to optimize this away. | ||
598 | * | ||
599 | * Since we're holding a reference ourselves, observing a refcount of 1 | ||
600 | * means that we're the last holder and can skip it. Also, the refcount | ||
601 | * can never increase from 1 again, so we don't need any barriers or | ||
602 | * locks. | ||
603 | * | ||
604 | * Note that userspace could try to race with use and instate a new | ||
605 | * usage _after_ we've cleared all current ones. End result will be an | ||
606 | * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot | ||
607 | * in this manner. | ||
608 | */ | ||
609 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
610 | drm_modeset_lock_all(dev); | ||
611 | /* remove from any CRTC */ | ||
612 | drm_for_each_crtc(crtc, dev) { | ||
613 | if (crtc->primary->fb == fb) { | ||
614 | /* should turn off the crtc */ | ||
615 | if (drm_crtc_force_disable(crtc)) | ||
616 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | drm_for_each_plane(plane, dev) { | ||
621 | if (plane->fb == fb) | ||
622 | drm_plane_force_disable(plane); | ||
623 | } | ||
624 | drm_modeset_unlock_all(dev); | ||
625 | } | ||
626 | |||
627 | drm_framebuffer_unreference(fb); | ||
628 | } | ||
629 | EXPORT_SYMBOL(drm_framebuffer_remove); | ||
630 | |||
631 | DEFINE_WW_CLASS(crtc_ww_class); | 434 | DEFINE_WW_CLASS(crtc_ww_class); |
632 | 435 | ||
633 | static unsigned int drm_num_crtcs(struct drm_device *dev) | 436 | static unsigned int drm_num_crtcs(struct drm_device *dev) |
@@ -3011,7 +2814,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, | |||
3011 | */ | 2814 | */ |
3012 | if (req->flags & DRM_MODE_CURSOR_BO) { | 2815 | if (req->flags & DRM_MODE_CURSOR_BO) { |
3013 | if (req->handle) { | 2816 | if (req->handle) { |
3014 | fb = internal_framebuffer_create(dev, &fbreq, file_priv); | 2817 | fb = drm_internal_framebuffer_create(dev, &fbreq, file_priv); |
3015 | if (IS_ERR(fb)) { | 2818 | if (IS_ERR(fb)) { |
3016 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); | 2819 | DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); |
3017 | return PTR_ERR(fb); | 2820 | return PTR_ERR(fb); |
@@ -3209,581 +3012,6 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) | |||
3209 | } | 3012 | } |
3210 | EXPORT_SYMBOL(drm_mode_legacy_fb_format); | 3013 | EXPORT_SYMBOL(drm_mode_legacy_fb_format); |
3211 | 3014 | ||
3212 | /** | ||
3213 | * drm_mode_addfb - add an FB to the graphics configuration | ||
3214 | * @dev: drm device for the ioctl | ||
3215 | * @data: data pointer for the ioctl | ||
3216 | * @file_priv: drm file for the ioctl call | ||
3217 | * | ||
3218 | * Add a new FB to the specified CRTC, given a user request. This is the | ||
3219 | * original addfb ioctl which only supported RGB formats. | ||
3220 | * | ||
3221 | * Called by the user via ioctl. | ||
3222 | * | ||
3223 | * Returns: | ||
3224 | * Zero on success, negative errno on failure. | ||
3225 | */ | ||
3226 | int drm_mode_addfb(struct drm_device *dev, | ||
3227 | void *data, struct drm_file *file_priv) | ||
3228 | { | ||
3229 | struct drm_mode_fb_cmd *or = data; | ||
3230 | struct drm_mode_fb_cmd2 r = {}; | ||
3231 | int ret; | ||
3232 | |||
3233 | /* convert to new format and call new ioctl */ | ||
3234 | r.fb_id = or->fb_id; | ||
3235 | r.width = or->width; | ||
3236 | r.height = or->height; | ||
3237 | r.pitches[0] = or->pitch; | ||
3238 | r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); | ||
3239 | r.handles[0] = or->handle; | ||
3240 | |||
3241 | ret = drm_mode_addfb2(dev, &r, file_priv); | ||
3242 | if (ret) | ||
3243 | return ret; | ||
3244 | |||
3245 | or->fb_id = r.fb_id; | ||
3246 | |||
3247 | return 0; | ||
3248 | } | ||
3249 | |||
3250 | static int format_check(const struct drm_mode_fb_cmd2 *r) | ||
3251 | { | ||
3252 | uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; | ||
3253 | char *format_name; | ||
3254 | |||
3255 | switch (format) { | ||
3256 | case DRM_FORMAT_C8: | ||
3257 | case DRM_FORMAT_RGB332: | ||
3258 | case DRM_FORMAT_BGR233: | ||
3259 | case DRM_FORMAT_XRGB4444: | ||
3260 | case DRM_FORMAT_XBGR4444: | ||
3261 | case DRM_FORMAT_RGBX4444: | ||
3262 | case DRM_FORMAT_BGRX4444: | ||
3263 | case DRM_FORMAT_ARGB4444: | ||
3264 | case DRM_FORMAT_ABGR4444: | ||
3265 | case DRM_FORMAT_RGBA4444: | ||
3266 | case DRM_FORMAT_BGRA4444: | ||
3267 | case DRM_FORMAT_XRGB1555: | ||
3268 | case DRM_FORMAT_XBGR1555: | ||
3269 | case DRM_FORMAT_RGBX5551: | ||
3270 | case DRM_FORMAT_BGRX5551: | ||
3271 | case DRM_FORMAT_ARGB1555: | ||
3272 | case DRM_FORMAT_ABGR1555: | ||
3273 | case DRM_FORMAT_RGBA5551: | ||
3274 | case DRM_FORMAT_BGRA5551: | ||
3275 | case DRM_FORMAT_RGB565: | ||
3276 | case DRM_FORMAT_BGR565: | ||
3277 | case DRM_FORMAT_RGB888: | ||
3278 | case DRM_FORMAT_BGR888: | ||
3279 | case DRM_FORMAT_XRGB8888: | ||
3280 | case DRM_FORMAT_XBGR8888: | ||
3281 | case DRM_FORMAT_RGBX8888: | ||
3282 | case DRM_FORMAT_BGRX8888: | ||
3283 | case DRM_FORMAT_ARGB8888: | ||
3284 | case DRM_FORMAT_ABGR8888: | ||
3285 | case DRM_FORMAT_RGBA8888: | ||
3286 | case DRM_FORMAT_BGRA8888: | ||
3287 | case DRM_FORMAT_XRGB2101010: | ||
3288 | case DRM_FORMAT_XBGR2101010: | ||
3289 | case DRM_FORMAT_RGBX1010102: | ||
3290 | case DRM_FORMAT_BGRX1010102: | ||
3291 | case DRM_FORMAT_ARGB2101010: | ||
3292 | case DRM_FORMAT_ABGR2101010: | ||
3293 | case DRM_FORMAT_RGBA1010102: | ||
3294 | case DRM_FORMAT_BGRA1010102: | ||
3295 | case DRM_FORMAT_YUYV: | ||
3296 | case DRM_FORMAT_YVYU: | ||
3297 | case DRM_FORMAT_UYVY: | ||
3298 | case DRM_FORMAT_VYUY: | ||
3299 | case DRM_FORMAT_AYUV: | ||
3300 | case DRM_FORMAT_NV12: | ||
3301 | case DRM_FORMAT_NV21: | ||
3302 | case DRM_FORMAT_NV16: | ||
3303 | case DRM_FORMAT_NV61: | ||
3304 | case DRM_FORMAT_NV24: | ||
3305 | case DRM_FORMAT_NV42: | ||
3306 | case DRM_FORMAT_YUV410: | ||
3307 | case DRM_FORMAT_YVU410: | ||
3308 | case DRM_FORMAT_YUV411: | ||
3309 | case DRM_FORMAT_YVU411: | ||
3310 | case DRM_FORMAT_YUV420: | ||
3311 | case DRM_FORMAT_YVU420: | ||
3312 | case DRM_FORMAT_YUV422: | ||
3313 | case DRM_FORMAT_YVU422: | ||
3314 | case DRM_FORMAT_YUV444: | ||
3315 | case DRM_FORMAT_YVU444: | ||
3316 | return 0; | ||
3317 | default: | ||
3318 | format_name = drm_get_format_name(r->pixel_format); | ||
3319 | DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); | ||
3320 | kfree(format_name); | ||
3321 | return -EINVAL; | ||
3322 | } | ||
3323 | } | ||
3324 | |||
3325 | static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | ||
3326 | { | ||
3327 | int ret, hsub, vsub, num_planes, i; | ||
3328 | |||
3329 | ret = format_check(r); | ||
3330 | if (ret) { | ||
3331 | char *format_name = drm_get_format_name(r->pixel_format); | ||
3332 | DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); | ||
3333 | kfree(format_name); | ||
3334 | return ret; | ||
3335 | } | ||
3336 | |||
3337 | hsub = drm_format_horz_chroma_subsampling(r->pixel_format); | ||
3338 | vsub = drm_format_vert_chroma_subsampling(r->pixel_format); | ||
3339 | num_planes = drm_format_num_planes(r->pixel_format); | ||
3340 | |||
3341 | if (r->width == 0 || r->width % hsub) { | ||
3342 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); | ||
3343 | return -EINVAL; | ||
3344 | } | ||
3345 | |||
3346 | if (r->height == 0 || r->height % vsub) { | ||
3347 | DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); | ||
3348 | return -EINVAL; | ||
3349 | } | ||
3350 | |||
3351 | for (i = 0; i < num_planes; i++) { | ||
3352 | unsigned int width = r->width / (i != 0 ? hsub : 1); | ||
3353 | unsigned int height = r->height / (i != 0 ? vsub : 1); | ||
3354 | unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); | ||
3355 | |||
3356 | if (!r->handles[i]) { | ||
3357 | DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); | ||
3358 | return -EINVAL; | ||
3359 | } | ||
3360 | |||
3361 | if ((uint64_t) width * cpp > UINT_MAX) | ||
3362 | return -ERANGE; | ||
3363 | |||
3364 | if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) | ||
3365 | return -ERANGE; | ||
3366 | |||
3367 | if (r->pitches[i] < width * cpp) { | ||
3368 | DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); | ||
3369 | return -EINVAL; | ||
3370 | } | ||
3371 | |||
3372 | if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { | ||
3373 | DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", | ||
3374 | r->modifier[i], i); | ||
3375 | return -EINVAL; | ||
3376 | } | ||
3377 | |||
3378 | /* modifier specific checks: */ | ||
3379 | switch (r->modifier[i]) { | ||
3380 | case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: | ||
3381 | /* NOTE: the pitch restriction may be lifted later if it turns | ||
3382 | * out that no hw has this restriction: | ||
3383 | */ | ||
3384 | if (r->pixel_format != DRM_FORMAT_NV12 || | ||
3385 | width % 128 || height % 32 || | ||
3386 | r->pitches[i] % 128) { | ||
3387 | DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); | ||
3388 | return -EINVAL; | ||
3389 | } | ||
3390 | break; | ||
3391 | |||
3392 | default: | ||
3393 | break; | ||
3394 | } | ||
3395 | } | ||
3396 | |||
3397 | for (i = num_planes; i < 4; i++) { | ||
3398 | if (r->modifier[i]) { | ||
3399 | DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); | ||
3400 | return -EINVAL; | ||
3401 | } | ||
3402 | |||
3403 | /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ | ||
3404 | if (!(r->flags & DRM_MODE_FB_MODIFIERS)) | ||
3405 | continue; | ||
3406 | |||
3407 | if (r->handles[i]) { | ||
3408 | DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); | ||
3409 | return -EINVAL; | ||
3410 | } | ||
3411 | |||
3412 | if (r->pitches[i]) { | ||
3413 | DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); | ||
3414 | return -EINVAL; | ||
3415 | } | ||
3416 | |||
3417 | if (r->offsets[i]) { | ||
3418 | DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); | ||
3419 | return -EINVAL; | ||
3420 | } | ||
3421 | } | ||
3422 | |||
3423 | return 0; | ||
3424 | } | ||
3425 | |||
3426 | static struct drm_framebuffer * | ||
3427 | internal_framebuffer_create(struct drm_device *dev, | ||
3428 | const struct drm_mode_fb_cmd2 *r, | ||
3429 | struct drm_file *file_priv) | ||
3430 | { | ||
3431 | struct drm_mode_config *config = &dev->mode_config; | ||
3432 | struct drm_framebuffer *fb; | ||
3433 | int ret; | ||
3434 | |||
3435 | if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { | ||
3436 | DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); | ||
3437 | return ERR_PTR(-EINVAL); | ||
3438 | } | ||
3439 | |||
3440 | if ((config->min_width > r->width) || (r->width > config->max_width)) { | ||
3441 | DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", | ||
3442 | r->width, config->min_width, config->max_width); | ||
3443 | return ERR_PTR(-EINVAL); | ||
3444 | } | ||
3445 | if ((config->min_height > r->height) || (r->height > config->max_height)) { | ||
3446 | DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", | ||
3447 | r->height, config->min_height, config->max_height); | ||
3448 | return ERR_PTR(-EINVAL); | ||
3449 | } | ||
3450 | |||
3451 | if (r->flags & DRM_MODE_FB_MODIFIERS && | ||
3452 | !dev->mode_config.allow_fb_modifiers) { | ||
3453 | DRM_DEBUG_KMS("driver does not support fb modifiers\n"); | ||
3454 | return ERR_PTR(-EINVAL); | ||
3455 | } | ||
3456 | |||
3457 | ret = framebuffer_check(r); | ||
3458 | if (ret) | ||
3459 | return ERR_PTR(ret); | ||
3460 | |||
3461 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); | ||
3462 | if (IS_ERR(fb)) { | ||
3463 | DRM_DEBUG_KMS("could not create framebuffer\n"); | ||
3464 | return fb; | ||
3465 | } | ||
3466 | |||
3467 | return fb; | ||
3468 | } | ||
3469 | |||
3470 | /** | ||
3471 | * drm_mode_addfb2 - add an FB to the graphics configuration | ||
3472 | * @dev: drm device for the ioctl | ||
3473 | * @data: data pointer for the ioctl | ||
3474 | * @file_priv: drm file for the ioctl call | ||
3475 | * | ||
3476 | * Add a new FB to the specified CRTC, given a user request with format. This is | ||
3477 | * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers | ||
3478 | * and uses fourcc codes as pixel format specifiers. | ||
3479 | * | ||
3480 | * Called by the user via ioctl. | ||
3481 | * | ||
3482 | * Returns: | ||
3483 | * Zero on success, negative errno on failure. | ||
3484 | */ | ||
3485 | int drm_mode_addfb2(struct drm_device *dev, | ||
3486 | void *data, struct drm_file *file_priv) | ||
3487 | { | ||
3488 | struct drm_mode_fb_cmd2 *r = data; | ||
3489 | struct drm_framebuffer *fb; | ||
3490 | |||
3491 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3492 | return -EINVAL; | ||
3493 | |||
3494 | fb = internal_framebuffer_create(dev, r, file_priv); | ||
3495 | if (IS_ERR(fb)) | ||
3496 | return PTR_ERR(fb); | ||
3497 | |||
3498 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); | ||
3499 | r->fb_id = fb->base.id; | ||
3500 | |||
3501 | /* Transfer ownership to the filp for reaping on close */ | ||
3502 | mutex_lock(&file_priv->fbs_lock); | ||
3503 | list_add(&fb->filp_head, &file_priv->fbs); | ||
3504 | mutex_unlock(&file_priv->fbs_lock); | ||
3505 | |||
3506 | return 0; | ||
3507 | } | ||
3508 | |||
3509 | struct drm_mode_rmfb_work { | ||
3510 | struct work_struct work; | ||
3511 | struct list_head fbs; | ||
3512 | }; | ||
3513 | |||
3514 | static void drm_mode_rmfb_work_fn(struct work_struct *w) | ||
3515 | { | ||
3516 | struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); | ||
3517 | |||
3518 | while (!list_empty(&arg->fbs)) { | ||
3519 | struct drm_framebuffer *fb = | ||
3520 | list_first_entry(&arg->fbs, typeof(*fb), filp_head); | ||
3521 | |||
3522 | list_del_init(&fb->filp_head); | ||
3523 | drm_framebuffer_remove(fb); | ||
3524 | } | ||
3525 | } | ||
3526 | |||
3527 | /** | ||
3528 | * drm_mode_rmfb - remove an FB from the configuration | ||
3529 | * @dev: drm device for the ioctl | ||
3530 | * @data: data pointer for the ioctl | ||
3531 | * @file_priv: drm file for the ioctl call | ||
3532 | * | ||
3533 | * Remove the FB specified by the user. | ||
3534 | * | ||
3535 | * Called by the user via ioctl. | ||
3536 | * | ||
3537 | * Returns: | ||
3538 | * Zero on success, negative errno on failure. | ||
3539 | */ | ||
3540 | int drm_mode_rmfb(struct drm_device *dev, | ||
3541 | void *data, struct drm_file *file_priv) | ||
3542 | { | ||
3543 | struct drm_framebuffer *fb = NULL; | ||
3544 | struct drm_framebuffer *fbl = NULL; | ||
3545 | uint32_t *id = data; | ||
3546 | int found = 0; | ||
3547 | |||
3548 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3549 | return -EINVAL; | ||
3550 | |||
3551 | fb = drm_framebuffer_lookup(dev, *id); | ||
3552 | if (!fb) | ||
3553 | return -ENOENT; | ||
3554 | |||
3555 | mutex_lock(&file_priv->fbs_lock); | ||
3556 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) | ||
3557 | if (fb == fbl) | ||
3558 | found = 1; | ||
3559 | if (!found) { | ||
3560 | mutex_unlock(&file_priv->fbs_lock); | ||
3561 | goto fail_unref; | ||
3562 | } | ||
3563 | |||
3564 | list_del_init(&fb->filp_head); | ||
3565 | mutex_unlock(&file_priv->fbs_lock); | ||
3566 | |||
3567 | /* drop the reference we picked up in framebuffer lookup */ | ||
3568 | drm_framebuffer_unreference(fb); | ||
3569 | |||
3570 | /* | ||
3571 | * we now own the reference that was stored in the fbs list | ||
3572 | * | ||
3573 | * drm_framebuffer_remove may fail with -EINTR on pending signals, | ||
3574 | * so run this in a separate stack as there's no way to correctly | ||
3575 | * handle this after the fb is already removed from the lookup table. | ||
3576 | */ | ||
3577 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
3578 | struct drm_mode_rmfb_work arg; | ||
3579 | |||
3580 | INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); | ||
3581 | INIT_LIST_HEAD(&arg.fbs); | ||
3582 | list_add_tail(&fb->filp_head, &arg.fbs); | ||
3583 | |||
3584 | schedule_work(&arg.work); | ||
3585 | flush_work(&arg.work); | ||
3586 | destroy_work_on_stack(&arg.work); | ||
3587 | } else | ||
3588 | drm_framebuffer_unreference(fb); | ||
3589 | |||
3590 | return 0; | ||
3591 | |||
3592 | fail_unref: | ||
3593 | drm_framebuffer_unreference(fb); | ||
3594 | return -ENOENT; | ||
3595 | } | ||
3596 | |||
3597 | /** | ||
3598 | * drm_mode_getfb - get FB info | ||
3599 | * @dev: drm device for the ioctl | ||
3600 | * @data: data pointer for the ioctl | ||
3601 | * @file_priv: drm file for the ioctl call | ||
3602 | * | ||
3603 | * Lookup the FB given its ID and return info about it. | ||
3604 | * | ||
3605 | * Called by the user via ioctl. | ||
3606 | * | ||
3607 | * Returns: | ||
3608 | * Zero on success, negative errno on failure. | ||
3609 | */ | ||
3610 | int drm_mode_getfb(struct drm_device *dev, | ||
3611 | void *data, struct drm_file *file_priv) | ||
3612 | { | ||
3613 | struct drm_mode_fb_cmd *r = data; | ||
3614 | struct drm_framebuffer *fb; | ||
3615 | int ret; | ||
3616 | |||
3617 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3618 | return -EINVAL; | ||
3619 | |||
3620 | fb = drm_framebuffer_lookup(dev, r->fb_id); | ||
3621 | if (!fb) | ||
3622 | return -ENOENT; | ||
3623 | |||
3624 | r->height = fb->height; | ||
3625 | r->width = fb->width; | ||
3626 | r->depth = fb->depth; | ||
3627 | r->bpp = fb->bits_per_pixel; | ||
3628 | r->pitch = fb->pitches[0]; | ||
3629 | if (fb->funcs->create_handle) { | ||
3630 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || | ||
3631 | drm_is_control_client(file_priv)) { | ||
3632 | ret = fb->funcs->create_handle(fb, file_priv, | ||
3633 | &r->handle); | ||
3634 | } else { | ||
3635 | /* GET_FB() is an unprivileged ioctl so we must not | ||
3636 | * return a buffer-handle to non-master processes! For | ||
3637 | * backwards-compatibility reasons, we cannot make | ||
3638 | * GET_FB() privileged, so just return an invalid handle | ||
3639 | * for non-masters. */ | ||
3640 | r->handle = 0; | ||
3641 | ret = 0; | ||
3642 | } | ||
3643 | } else { | ||
3644 | ret = -ENODEV; | ||
3645 | } | ||
3646 | |||
3647 | drm_framebuffer_unreference(fb); | ||
3648 | |||
3649 | return ret; | ||
3650 | } | ||
3651 | |||
3652 | /** | ||
3653 | * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB | ||
3654 | * @dev: drm device for the ioctl | ||
3655 | * @data: data pointer for the ioctl | ||
3656 | * @file_priv: drm file for the ioctl call | ||
3657 | * | ||
3658 | * Lookup the FB and flush out the damaged area supplied by userspace as a clip | ||
3659 | * rectangle list. Generic userspace which does frontbuffer rendering must call | ||
3660 | * this ioctl to flush out the changes on manual-update display outputs, e.g. | ||
3661 | * usb display-link, mipi manual update panels or edp panel self refresh modes. | ||
3662 | * | ||
3663 | * Modesetting drivers which always update the frontbuffer do not need to | ||
3664 | * implement the corresponding ->dirty framebuffer callback. | ||
3665 | * | ||
3666 | * Called by the user via ioctl. | ||
3667 | * | ||
3668 | * Returns: | ||
3669 | * Zero on success, negative errno on failure. | ||
3670 | */ | ||
3671 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
3672 | void *data, struct drm_file *file_priv) | ||
3673 | { | ||
3674 | struct drm_clip_rect __user *clips_ptr; | ||
3675 | struct drm_clip_rect *clips = NULL; | ||
3676 | struct drm_mode_fb_dirty_cmd *r = data; | ||
3677 | struct drm_framebuffer *fb; | ||
3678 | unsigned flags; | ||
3679 | int num_clips; | ||
3680 | int ret; | ||
3681 | |||
3682 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3683 | return -EINVAL; | ||
3684 | |||
3685 | fb = drm_framebuffer_lookup(dev, r->fb_id); | ||
3686 | if (!fb) | ||
3687 | return -ENOENT; | ||
3688 | |||
3689 | num_clips = r->num_clips; | ||
3690 | clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; | ||
3691 | |||
3692 | if (!num_clips != !clips_ptr) { | ||
3693 | ret = -EINVAL; | ||
3694 | goto out_err1; | ||
3695 | } | ||
3696 | |||
3697 | flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; | ||
3698 | |||
3699 | /* If userspace annotates copy, clips must come in pairs */ | ||
3700 | if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { | ||
3701 | ret = -EINVAL; | ||
3702 | goto out_err1; | ||
3703 | } | ||
3704 | |||
3705 | if (num_clips && clips_ptr) { | ||
3706 | if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { | ||
3707 | ret = -EINVAL; | ||
3708 | goto out_err1; | ||
3709 | } | ||
3710 | clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); | ||
3711 | if (!clips) { | ||
3712 | ret = -ENOMEM; | ||
3713 | goto out_err1; | ||
3714 | } | ||
3715 | |||
3716 | ret = copy_from_user(clips, clips_ptr, | ||
3717 | num_clips * sizeof(*clips)); | ||
3718 | if (ret) { | ||
3719 | ret = -EFAULT; | ||
3720 | goto out_err2; | ||
3721 | } | ||
3722 | } | ||
3723 | |||
3724 | if (fb->funcs->dirty) { | ||
3725 | ret = fb->funcs->dirty(fb, file_priv, flags, r->color, | ||
3726 | clips, num_clips); | ||
3727 | } else { | ||
3728 | ret = -ENOSYS; | ||
3729 | } | ||
3730 | |||
3731 | out_err2: | ||
3732 | kfree(clips); | ||
3733 | out_err1: | ||
3734 | drm_framebuffer_unreference(fb); | ||
3735 | |||
3736 | return ret; | ||
3737 | } | ||
3738 | |||
3739 | /** | ||
3740 | * drm_fb_release - remove and free the FBs on this file | ||
3741 | * @priv: drm file for the ioctl | ||
3742 | * | ||
3743 | * Destroy all the FBs associated with @filp. | ||
3744 | * | ||
3745 | * Called by the user via ioctl. | ||
3746 | * | ||
3747 | * Returns: | ||
3748 | * Zero on success, negative errno on failure. | ||
3749 | */ | ||
3750 | void drm_fb_release(struct drm_file *priv) | ||
3751 | { | ||
3752 | struct drm_framebuffer *fb, *tfb; | ||
3753 | struct drm_mode_rmfb_work arg; | ||
3754 | |||
3755 | INIT_LIST_HEAD(&arg.fbs); | ||
3756 | |||
3757 | /* | ||
3758 | * When the file gets released that means no one else can access the fb | ||
3759 | * list any more, so no need to grab fpriv->fbs_lock. And we need to | ||
3760 | * avoid upsetting lockdep since the universal cursor code adds a | ||
3761 | * framebuffer while holding mutex locks. | ||
3762 | * | ||
3763 | * Note that a real deadlock between fpriv->fbs_lock and the modeset | ||
3764 | * locks is impossible here since no one else but this function can get | ||
3765 | * at it any more. | ||
3766 | */ | ||
3767 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | ||
3768 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
3769 | list_move_tail(&fb->filp_head, &arg.fbs); | ||
3770 | } else { | ||
3771 | list_del_init(&fb->filp_head); | ||
3772 | |||
3773 | /* This drops the fpriv->fbs reference. */ | ||
3774 | drm_framebuffer_unreference(fb); | ||
3775 | } | ||
3776 | } | ||
3777 | |||
3778 | if (!list_empty(&arg.fbs)) { | ||
3779 | INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); | ||
3780 | |||
3781 | schedule_work(&arg.work); | ||
3782 | flush_work(&arg.work); | ||
3783 | destroy_work_on_stack(&arg.work); | ||
3784 | } | ||
3785 | } | ||
3786 | |||
3787 | static bool drm_property_type_valid(struct drm_property *property) | 3015 | static bool drm_property_type_valid(struct drm_property *property) |
3788 | { | 3016 | { |
3789 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) | 3017 | if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) |
@@ -4496,7 +3724,7 @@ struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, | |||
4496 | struct drm_mode_object *obj; | 3724 | struct drm_mode_object *obj; |
4497 | struct drm_property_blob *blob = NULL; | 3725 | struct drm_property_blob *blob = NULL; |
4498 | 3726 | ||
4499 | obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB); | 3727 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB); |
4500 | if (obj) | 3728 | if (obj) |
4501 | blob = obj_to_blob(obj); | 3729 | blob = obj_to_blob(obj); |
4502 | return blob; | 3730 | return blob; |
@@ -4892,7 +4120,8 @@ bool drm_property_change_valid_get(struct drm_property *property, | |||
4892 | if (value == 0) | 4120 | if (value == 0) |
4893 | return true; | 4121 | return true; |
4894 | 4122 | ||
4895 | *ref = _object_find(property->dev, value, property->values[0]); | 4123 | *ref = __drm_mode_object_find(property->dev, value, |
4124 | property->values[0]); | ||
4896 | return *ref != NULL; | 4125 | return *ref != NULL; |
4897 | } | 4126 | } |
4898 | 4127 | ||