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 | |
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>
-rw-r--r-- | Documentation/gpu/drm-kms.rst | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 801 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc_internal.h | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_framebuffer.c | 796 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 162 | ||||
-rw-r--r-- | include/drm/drm_framebuffer.h | 170 | ||||
-rw-r--r-- | include/drm/drm_modes.h | 2 | ||||
-rw-r--r-- | include/drm/drm_modeset.h | 50 |
9 files changed, 1075 insertions, 958 deletions
diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 3ae4c12aca08..8264a88a8695 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst | |||
@@ -64,6 +64,15 @@ fbdev framebuffer when the struct :c:type:`struct drm_framebuffer | |||
64 | drivers can manually clean up a framebuffer at module unload time with | 64 | drivers can manually clean up a framebuffer at module unload time with |
65 | :c:func:`drm_framebuffer_unregister_private()`. | 65 | :c:func:`drm_framebuffer_unregister_private()`. |
66 | 66 | ||
67 | Frame Buffer Functions Reference | ||
68 | -------------------------------- | ||
69 | |||
70 | .. kernel-doc:: drivers/gpu/drm/drm_framebuffer.c | ||
71 | :export: | ||
72 | |||
73 | .. kernel-doc:: include/drm/drm_framebuffer.h | ||
74 | :internal: | ||
75 | |||
67 | DRM Format Handling | 76 | DRM Format Handling |
68 | =================== | 77 | =================== |
69 | 78 | ||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a5824d926dc9..c71ec42ce511 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -12,7 +12,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
12 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ | 12 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ |
13 | drm_trace_points.o drm_global.o drm_prime.o \ | 13 | drm_trace_points.o drm_global.o drm_prime.o \ |
14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ | 14 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o | 15 | drm_modeset_lock.o drm_atomic.o drm_bridge.o \ |
16 | drm_framebuffer.o | ||
16 | 17 | ||
17 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 18 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
18 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 19 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
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 | ||
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 0c34e6d906d1..67a7b4540630 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h | |||
@@ -35,8 +35,17 @@ | |||
35 | /* drm_crtc.c */ | 35 | /* drm_crtc.c */ |
36 | void drm_connector_ida_init(void); | 36 | void drm_connector_ida_init(void); |
37 | void drm_connector_ida_destroy(void); | 37 | void drm_connector_ida_destroy(void); |
38 | int drm_mode_object_get_reg(struct drm_device *dev, | ||
39 | struct drm_mode_object *obj, | ||
40 | uint32_t obj_type, | ||
41 | bool register_obj, | ||
42 | void (*obj_free_cb)(struct kref *kref)); | ||
43 | void drm_mode_object_register(struct drm_device *dev, | ||
44 | struct drm_mode_object *obj); | ||
38 | int drm_mode_object_get(struct drm_device *dev, | 45 | int drm_mode_object_get(struct drm_device *dev, |
39 | struct drm_mode_object *obj, uint32_t obj_type); | 46 | struct drm_mode_object *obj, uint32_t obj_type); |
47 | struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, | ||
48 | uint32_t id, uint32_t type); | ||
40 | void drm_mode_object_unregister(struct drm_device *dev, | 49 | void drm_mode_object_unregister(struct drm_device *dev, |
41 | struct drm_mode_object *object); | 50 | struct drm_mode_object *object); |
42 | bool drm_property_change_valid_get(struct drm_property *property, | 51 | bool drm_property_change_valid_get(struct drm_property *property, |
@@ -64,18 +73,6 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, | |||
64 | int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, | 73 | int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, |
65 | void *data, struct drm_file *file_priv); | 74 | void *data, struct drm_file *file_priv); |
66 | 75 | ||
67 | /* framebuffer IOCTLs */ | ||
68 | extern int drm_mode_addfb(struct drm_device *dev, | ||
69 | void *data, struct drm_file *file_priv); | ||
70 | extern int drm_mode_addfb2(struct drm_device *dev, | ||
71 | void *data, struct drm_file *file_priv); | ||
72 | int drm_mode_rmfb(struct drm_device *dev, | ||
73 | void *data, struct drm_file *file_priv); | ||
74 | int drm_mode_getfb(struct drm_device *dev, | ||
75 | void *data, struct drm_file *file_priv); | ||
76 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
77 | void *data, struct drm_file *file_priv); | ||
78 | |||
79 | /* IOCTLs */ | 76 | /* IOCTLs */ |
80 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, | 77 | int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, |
81 | struct drm_file *file_priv); | 78 | struct drm_file *file_priv); |
@@ -120,6 +117,25 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, | |||
120 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | 117 | int drm_mode_page_flip_ioctl(struct drm_device *dev, |
121 | void *data, struct drm_file *file_priv); | 118 | void *data, struct drm_file *file_priv); |
122 | 119 | ||
120 | /* drm_framebuffer.c */ | ||
121 | struct drm_framebuffer * | ||
122 | drm_internal_framebuffer_create(struct drm_device *dev, | ||
123 | const struct drm_mode_fb_cmd2 *r, | ||
124 | struct drm_file *file_priv); | ||
125 | void drm_framebuffer_free(struct kref *kref); | ||
126 | |||
127 | /* IOCTL */ | ||
128 | int drm_mode_addfb(struct drm_device *dev, | ||
129 | void *data, struct drm_file *file_priv); | ||
130 | int drm_mode_addfb2(struct drm_device *dev, | ||
131 | void *data, struct drm_file *file_priv); | ||
132 | int drm_mode_rmfb(struct drm_device *dev, | ||
133 | void *data, struct drm_file *file_priv); | ||
134 | int drm_mode_getfb(struct drm_device *dev, | ||
135 | void *data, struct drm_file *file_priv); | ||
136 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
137 | void *data, struct drm_file *file_priv); | ||
138 | |||
123 | /* drm_atomic.c */ | 139 | /* drm_atomic.c */ |
124 | int drm_atomic_get_property(struct drm_mode_object *obj, | 140 | int drm_atomic_get_property(struct drm_mode_object *obj, |
125 | struct drm_property *property, uint64_t *val); | 141 | struct drm_property *property, uint64_t *val); |
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c new file mode 100644 index 000000000000..74572c8a50b8 --- /dev/null +++ b/drivers/gpu/drm/drm_framebuffer.c | |||
@@ -0,0 +1,796 @@ | |||
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 <drm/drmP.h> | ||
25 | #include <drm/drm_auth.h> | ||
26 | #include <drm/drm_framebuffer.h> | ||
27 | |||
28 | #include "drm_crtc_internal.h" | ||
29 | |||
30 | /** | ||
31 | * drm_mode_addfb - add an FB to the graphics configuration | ||
32 | * @dev: drm device for the ioctl | ||
33 | * @data: data pointer for the ioctl | ||
34 | * @file_priv: drm file for the ioctl call | ||
35 | * | ||
36 | * Add a new FB to the specified CRTC, given a user request. This is the | ||
37 | * original addfb ioctl which only supported RGB formats. | ||
38 | * | ||
39 | * Called by the user via ioctl. | ||
40 | * | ||
41 | * Returns: | ||
42 | * Zero on success, negative errno on failure. | ||
43 | */ | ||
44 | int drm_mode_addfb(struct drm_device *dev, | ||
45 | void *data, struct drm_file *file_priv) | ||
46 | { | ||
47 | struct drm_mode_fb_cmd *or = data; | ||
48 | struct drm_mode_fb_cmd2 r = {}; | ||
49 | int ret; | ||
50 | |||
51 | /* convert to new format and call new ioctl */ | ||
52 | r.fb_id = or->fb_id; | ||
53 | r.width = or->width; | ||
54 | r.height = or->height; | ||
55 | r.pitches[0] = or->pitch; | ||
56 | r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); | ||
57 | r.handles[0] = or->handle; | ||
58 | |||
59 | ret = drm_mode_addfb2(dev, &r, file_priv); | ||
60 | if (ret) | ||
61 | return ret; | ||
62 | |||
63 | or->fb_id = r.fb_id; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int format_check(const struct drm_mode_fb_cmd2 *r) | ||
69 | { | ||
70 | uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; | ||
71 | char *format_name; | ||
72 | |||
73 | switch (format) { | ||
74 | case DRM_FORMAT_C8: | ||
75 | case DRM_FORMAT_RGB332: | ||
76 | case DRM_FORMAT_BGR233: | ||
77 | case DRM_FORMAT_XRGB4444: | ||
78 | case DRM_FORMAT_XBGR4444: | ||
79 | case DRM_FORMAT_RGBX4444: | ||
80 | case DRM_FORMAT_BGRX4444: | ||
81 | case DRM_FORMAT_ARGB4444: | ||
82 | case DRM_FORMAT_ABGR4444: | ||
83 | case DRM_FORMAT_RGBA4444: | ||
84 | case DRM_FORMAT_BGRA4444: | ||
85 | case DRM_FORMAT_XRGB1555: | ||
86 | case DRM_FORMAT_XBGR1555: | ||
87 | case DRM_FORMAT_RGBX5551: | ||
88 | case DRM_FORMAT_BGRX5551: | ||
89 | case DRM_FORMAT_ARGB1555: | ||
90 | case DRM_FORMAT_ABGR1555: | ||
91 | case DRM_FORMAT_RGBA5551: | ||
92 | case DRM_FORMAT_BGRA5551: | ||
93 | case DRM_FORMAT_RGB565: | ||
94 | case DRM_FORMAT_BGR565: | ||
95 | case DRM_FORMAT_RGB888: | ||
96 | case DRM_FORMAT_BGR888: | ||
97 | case DRM_FORMAT_XRGB8888: | ||
98 | case DRM_FORMAT_XBGR8888: | ||
99 | case DRM_FORMAT_RGBX8888: | ||
100 | case DRM_FORMAT_BGRX8888: | ||
101 | case DRM_FORMAT_ARGB8888: | ||
102 | case DRM_FORMAT_ABGR8888: | ||
103 | case DRM_FORMAT_RGBA8888: | ||
104 | case DRM_FORMAT_BGRA8888: | ||
105 | case DRM_FORMAT_XRGB2101010: | ||
106 | case DRM_FORMAT_XBGR2101010: | ||
107 | case DRM_FORMAT_RGBX1010102: | ||
108 | case DRM_FORMAT_BGRX1010102: | ||
109 | case DRM_FORMAT_ARGB2101010: | ||
110 | case DRM_FORMAT_ABGR2101010: | ||
111 | case DRM_FORMAT_RGBA1010102: | ||
112 | case DRM_FORMAT_BGRA1010102: | ||
113 | case DRM_FORMAT_YUYV: | ||
114 | case DRM_FORMAT_YVYU: | ||
115 | case DRM_FORMAT_UYVY: | ||
116 | case DRM_FORMAT_VYUY: | ||
117 | case DRM_FORMAT_AYUV: | ||
118 | case DRM_FORMAT_NV12: | ||
119 | case DRM_FORMAT_NV21: | ||
120 | case DRM_FORMAT_NV16: | ||
121 | case DRM_FORMAT_NV61: | ||
122 | case DRM_FORMAT_NV24: | ||
123 | case DRM_FORMAT_NV42: | ||
124 | case DRM_FORMAT_YUV410: | ||
125 | case DRM_FORMAT_YVU410: | ||
126 | case DRM_FORMAT_YUV411: | ||
127 | case DRM_FORMAT_YVU411: | ||
128 | case DRM_FORMAT_YUV420: | ||
129 | case DRM_FORMAT_YVU420: | ||
130 | case DRM_FORMAT_YUV422: | ||
131 | case DRM_FORMAT_YVU422: | ||
132 | case DRM_FORMAT_YUV444: | ||
133 | case DRM_FORMAT_YVU444: | ||
134 | return 0; | ||
135 | default: | ||
136 | format_name = drm_get_format_name(r->pixel_format); | ||
137 | DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); | ||
138 | kfree(format_name); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | ||
144 | { | ||
145 | int ret, hsub, vsub, num_planes, i; | ||
146 | |||
147 | ret = format_check(r); | ||
148 | if (ret) { | ||
149 | char *format_name = drm_get_format_name(r->pixel_format); | ||
150 | DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); | ||
151 | kfree(format_name); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | hsub = drm_format_horz_chroma_subsampling(r->pixel_format); | ||
156 | vsub = drm_format_vert_chroma_subsampling(r->pixel_format); | ||
157 | num_planes = drm_format_num_planes(r->pixel_format); | ||
158 | |||
159 | if (r->width == 0 || r->width % hsub) { | ||
160 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | if (r->height == 0 || r->height % vsub) { | ||
165 | DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | for (i = 0; i < num_planes; i++) { | ||
170 | unsigned int width = r->width / (i != 0 ? hsub : 1); | ||
171 | unsigned int height = r->height / (i != 0 ? vsub : 1); | ||
172 | unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); | ||
173 | |||
174 | if (!r->handles[i]) { | ||
175 | DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | if ((uint64_t) width * cpp > UINT_MAX) | ||
180 | return -ERANGE; | ||
181 | |||
182 | if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) | ||
183 | return -ERANGE; | ||
184 | |||
185 | if (r->pitches[i] < width * cpp) { | ||
186 | DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) { | ||
191 | DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", | ||
192 | r->modifier[i], i); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | /* modifier specific checks: */ | ||
197 | switch (r->modifier[i]) { | ||
198 | case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: | ||
199 | /* NOTE: the pitch restriction may be lifted later if it turns | ||
200 | * out that no hw has this restriction: | ||
201 | */ | ||
202 | if (r->pixel_format != DRM_FORMAT_NV12 || | ||
203 | width % 128 || height % 32 || | ||
204 | r->pitches[i] % 128) { | ||
205 | DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | break; | ||
209 | |||
210 | default: | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | for (i = num_planes; i < 4; i++) { | ||
216 | if (r->modifier[i]) { | ||
217 | DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | /* Pre-FB_MODIFIERS userspace didn't clear the structs properly. */ | ||
222 | if (!(r->flags & DRM_MODE_FB_MODIFIERS)) | ||
223 | continue; | ||
224 | |||
225 | if (r->handles[i]) { | ||
226 | DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | if (r->pitches[i]) { | ||
231 | DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | if (r->offsets[i]) { | ||
236 | DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | struct drm_framebuffer * | ||
245 | drm_internal_framebuffer_create(struct drm_device *dev, | ||
246 | const struct drm_mode_fb_cmd2 *r, | ||
247 | struct drm_file *file_priv) | ||
248 | { | ||
249 | struct drm_mode_config *config = &dev->mode_config; | ||
250 | struct drm_framebuffer *fb; | ||
251 | int ret; | ||
252 | |||
253 | if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) { | ||
254 | DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); | ||
255 | return ERR_PTR(-EINVAL); | ||
256 | } | ||
257 | |||
258 | if ((config->min_width > r->width) || (r->width > config->max_width)) { | ||
259 | DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", | ||
260 | r->width, config->min_width, config->max_width); | ||
261 | return ERR_PTR(-EINVAL); | ||
262 | } | ||
263 | if ((config->min_height > r->height) || (r->height > config->max_height)) { | ||
264 | DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", | ||
265 | r->height, config->min_height, config->max_height); | ||
266 | return ERR_PTR(-EINVAL); | ||
267 | } | ||
268 | |||
269 | if (r->flags & DRM_MODE_FB_MODIFIERS && | ||
270 | !dev->mode_config.allow_fb_modifiers) { | ||
271 | DRM_DEBUG_KMS("driver does not support fb modifiers\n"); | ||
272 | return ERR_PTR(-EINVAL); | ||
273 | } | ||
274 | |||
275 | ret = framebuffer_check(r); | ||
276 | if (ret) | ||
277 | return ERR_PTR(ret); | ||
278 | |||
279 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); | ||
280 | if (IS_ERR(fb)) { | ||
281 | DRM_DEBUG_KMS("could not create framebuffer\n"); | ||
282 | return fb; | ||
283 | } | ||
284 | |||
285 | return fb; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * drm_mode_addfb2 - add an FB to the graphics configuration | ||
290 | * @dev: drm device for the ioctl | ||
291 | * @data: data pointer for the ioctl | ||
292 | * @file_priv: drm file for the ioctl call | ||
293 | * | ||
294 | * Add a new FB to the specified CRTC, given a user request with format. This is | ||
295 | * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers | ||
296 | * and uses fourcc codes as pixel format specifiers. | ||
297 | * | ||
298 | * Called by the user via ioctl. | ||
299 | * | ||
300 | * Returns: | ||
301 | * Zero on success, negative errno on failure. | ||
302 | */ | ||
303 | int drm_mode_addfb2(struct drm_device *dev, | ||
304 | void *data, struct drm_file *file_priv) | ||
305 | { | ||
306 | struct drm_mode_fb_cmd2 *r = data; | ||
307 | struct drm_framebuffer *fb; | ||
308 | |||
309 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
310 | return -EINVAL; | ||
311 | |||
312 | fb = drm_internal_framebuffer_create(dev, r, file_priv); | ||
313 | if (IS_ERR(fb)) | ||
314 | return PTR_ERR(fb); | ||
315 | |||
316 | DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); | ||
317 | r->fb_id = fb->base.id; | ||
318 | |||
319 | /* Transfer ownership to the filp for reaping on close */ | ||
320 | mutex_lock(&file_priv->fbs_lock); | ||
321 | list_add(&fb->filp_head, &file_priv->fbs); | ||
322 | mutex_unlock(&file_priv->fbs_lock); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | struct drm_mode_rmfb_work { | ||
328 | struct work_struct work; | ||
329 | struct list_head fbs; | ||
330 | }; | ||
331 | |||
332 | static void drm_mode_rmfb_work_fn(struct work_struct *w) | ||
333 | { | ||
334 | struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work); | ||
335 | |||
336 | while (!list_empty(&arg->fbs)) { | ||
337 | struct drm_framebuffer *fb = | ||
338 | list_first_entry(&arg->fbs, typeof(*fb), filp_head); | ||
339 | |||
340 | list_del_init(&fb->filp_head); | ||
341 | drm_framebuffer_remove(fb); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /** | ||
346 | * drm_mode_rmfb - remove an FB from the configuration | ||
347 | * @dev: drm device for the ioctl | ||
348 | * @data: data pointer for the ioctl | ||
349 | * @file_priv: drm file for the ioctl call | ||
350 | * | ||
351 | * Remove the FB specified by the user. | ||
352 | * | ||
353 | * Called by the user via ioctl. | ||
354 | * | ||
355 | * Returns: | ||
356 | * Zero on success, negative errno on failure. | ||
357 | */ | ||
358 | int drm_mode_rmfb(struct drm_device *dev, | ||
359 | void *data, struct drm_file *file_priv) | ||
360 | { | ||
361 | struct drm_framebuffer *fb = NULL; | ||
362 | struct drm_framebuffer *fbl = NULL; | ||
363 | uint32_t *id = data; | ||
364 | int found = 0; | ||
365 | |||
366 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
367 | return -EINVAL; | ||
368 | |||
369 | fb = drm_framebuffer_lookup(dev, *id); | ||
370 | if (!fb) | ||
371 | return -ENOENT; | ||
372 | |||
373 | mutex_lock(&file_priv->fbs_lock); | ||
374 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) | ||
375 | if (fb == fbl) | ||
376 | found = 1; | ||
377 | if (!found) { | ||
378 | mutex_unlock(&file_priv->fbs_lock); | ||
379 | goto fail_unref; | ||
380 | } | ||
381 | |||
382 | list_del_init(&fb->filp_head); | ||
383 | mutex_unlock(&file_priv->fbs_lock); | ||
384 | |||
385 | /* drop the reference we picked up in framebuffer lookup */ | ||
386 | drm_framebuffer_unreference(fb); | ||
387 | |||
388 | /* | ||
389 | * we now own the reference that was stored in the fbs list | ||
390 | * | ||
391 | * drm_framebuffer_remove may fail with -EINTR on pending signals, | ||
392 | * so run this in a separate stack as there's no way to correctly | ||
393 | * handle this after the fb is already removed from the lookup table. | ||
394 | */ | ||
395 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
396 | struct drm_mode_rmfb_work arg; | ||
397 | |||
398 | INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); | ||
399 | INIT_LIST_HEAD(&arg.fbs); | ||
400 | list_add_tail(&fb->filp_head, &arg.fbs); | ||
401 | |||
402 | schedule_work(&arg.work); | ||
403 | flush_work(&arg.work); | ||
404 | destroy_work_on_stack(&arg.work); | ||
405 | } else | ||
406 | drm_framebuffer_unreference(fb); | ||
407 | |||
408 | return 0; | ||
409 | |||
410 | fail_unref: | ||
411 | drm_framebuffer_unreference(fb); | ||
412 | return -ENOENT; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * drm_mode_getfb - get FB info | ||
417 | * @dev: drm device for the ioctl | ||
418 | * @data: data pointer for the ioctl | ||
419 | * @file_priv: drm file for the ioctl call | ||
420 | * | ||
421 | * Lookup the FB given its ID and return info about it. | ||
422 | * | ||
423 | * Called by the user via ioctl. | ||
424 | * | ||
425 | * Returns: | ||
426 | * Zero on success, negative errno on failure. | ||
427 | */ | ||
428 | int drm_mode_getfb(struct drm_device *dev, | ||
429 | void *data, struct drm_file *file_priv) | ||
430 | { | ||
431 | struct drm_mode_fb_cmd *r = data; | ||
432 | struct drm_framebuffer *fb; | ||
433 | int ret; | ||
434 | |||
435 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | fb = drm_framebuffer_lookup(dev, r->fb_id); | ||
439 | if (!fb) | ||
440 | return -ENOENT; | ||
441 | |||
442 | r->height = fb->height; | ||
443 | r->width = fb->width; | ||
444 | r->depth = fb->depth; | ||
445 | r->bpp = fb->bits_per_pixel; | ||
446 | r->pitch = fb->pitches[0]; | ||
447 | if (fb->funcs->create_handle) { | ||
448 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || | ||
449 | drm_is_control_client(file_priv)) { | ||
450 | ret = fb->funcs->create_handle(fb, file_priv, | ||
451 | &r->handle); | ||
452 | } else { | ||
453 | /* GET_FB() is an unprivileged ioctl so we must not | ||
454 | * return a buffer-handle to non-master processes! For | ||
455 | * backwards-compatibility reasons, we cannot make | ||
456 | * GET_FB() privileged, so just return an invalid handle | ||
457 | * for non-masters. */ | ||
458 | r->handle = 0; | ||
459 | ret = 0; | ||
460 | } | ||
461 | } else { | ||
462 | ret = -ENODEV; | ||
463 | } | ||
464 | |||
465 | drm_framebuffer_unreference(fb); | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB | ||
472 | * @dev: drm device for the ioctl | ||
473 | * @data: data pointer for the ioctl | ||
474 | * @file_priv: drm file for the ioctl call | ||
475 | * | ||
476 | * Lookup the FB and flush out the damaged area supplied by userspace as a clip | ||
477 | * rectangle list. Generic userspace which does frontbuffer rendering must call | ||
478 | * this ioctl to flush out the changes on manual-update display outputs, e.g. | ||
479 | * usb display-link, mipi manual update panels or edp panel self refresh modes. | ||
480 | * | ||
481 | * Modesetting drivers which always update the frontbuffer do not need to | ||
482 | * implement the corresponding ->dirty framebuffer callback. | ||
483 | * | ||
484 | * Called by the user via ioctl. | ||
485 | * | ||
486 | * Returns: | ||
487 | * Zero on success, negative errno on failure. | ||
488 | */ | ||
489 | int drm_mode_dirtyfb_ioctl(struct drm_device *dev, | ||
490 | void *data, struct drm_file *file_priv) | ||
491 | { | ||
492 | struct drm_clip_rect __user *clips_ptr; | ||
493 | struct drm_clip_rect *clips = NULL; | ||
494 | struct drm_mode_fb_dirty_cmd *r = data; | ||
495 | struct drm_framebuffer *fb; | ||
496 | unsigned flags; | ||
497 | int num_clips; | ||
498 | int ret; | ||
499 | |||
500 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
501 | return -EINVAL; | ||
502 | |||
503 | fb = drm_framebuffer_lookup(dev, r->fb_id); | ||
504 | if (!fb) | ||
505 | return -ENOENT; | ||
506 | |||
507 | num_clips = r->num_clips; | ||
508 | clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; | ||
509 | |||
510 | if (!num_clips != !clips_ptr) { | ||
511 | ret = -EINVAL; | ||
512 | goto out_err1; | ||
513 | } | ||
514 | |||
515 | flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags; | ||
516 | |||
517 | /* If userspace annotates copy, clips must come in pairs */ | ||
518 | if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { | ||
519 | ret = -EINVAL; | ||
520 | goto out_err1; | ||
521 | } | ||
522 | |||
523 | if (num_clips && clips_ptr) { | ||
524 | if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { | ||
525 | ret = -EINVAL; | ||
526 | goto out_err1; | ||
527 | } | ||
528 | clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); | ||
529 | if (!clips) { | ||
530 | ret = -ENOMEM; | ||
531 | goto out_err1; | ||
532 | } | ||
533 | |||
534 | ret = copy_from_user(clips, clips_ptr, | ||
535 | num_clips * sizeof(*clips)); | ||
536 | if (ret) { | ||
537 | ret = -EFAULT; | ||
538 | goto out_err2; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | if (fb->funcs->dirty) { | ||
543 | ret = fb->funcs->dirty(fb, file_priv, flags, r->color, | ||
544 | clips, num_clips); | ||
545 | } else { | ||
546 | ret = -ENOSYS; | ||
547 | } | ||
548 | |||
549 | out_err2: | ||
550 | kfree(clips); | ||
551 | out_err1: | ||
552 | drm_framebuffer_unreference(fb); | ||
553 | |||
554 | return ret; | ||
555 | } | ||
556 | |||
557 | /** | ||
558 | * drm_fb_release - remove and free the FBs on this file | ||
559 | * @priv: drm file for the ioctl | ||
560 | * | ||
561 | * Destroy all the FBs associated with @filp. | ||
562 | * | ||
563 | * Called by the user via ioctl. | ||
564 | * | ||
565 | * Returns: | ||
566 | * Zero on success, negative errno on failure. | ||
567 | */ | ||
568 | void drm_fb_release(struct drm_file *priv) | ||
569 | { | ||
570 | struct drm_framebuffer *fb, *tfb; | ||
571 | struct drm_mode_rmfb_work arg; | ||
572 | |||
573 | INIT_LIST_HEAD(&arg.fbs); | ||
574 | |||
575 | /* | ||
576 | * When the file gets released that means no one else can access the fb | ||
577 | * list any more, so no need to grab fpriv->fbs_lock. And we need to | ||
578 | * avoid upsetting lockdep since the universal cursor code adds a | ||
579 | * framebuffer while holding mutex locks. | ||
580 | * | ||
581 | * Note that a real deadlock between fpriv->fbs_lock and the modeset | ||
582 | * locks is impossible here since no one else but this function can get | ||
583 | * at it any more. | ||
584 | */ | ||
585 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | ||
586 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
587 | list_move_tail(&fb->filp_head, &arg.fbs); | ||
588 | } else { | ||
589 | list_del_init(&fb->filp_head); | ||
590 | |||
591 | /* This drops the fpriv->fbs reference. */ | ||
592 | drm_framebuffer_unreference(fb); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | if (!list_empty(&arg.fbs)) { | ||
597 | INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); | ||
598 | |||
599 | schedule_work(&arg.work); | ||
600 | flush_work(&arg.work); | ||
601 | destroy_work_on_stack(&arg.work); | ||
602 | } | ||
603 | } | ||
604 | |||
605 | void drm_framebuffer_free(struct kref *kref) | ||
606 | { | ||
607 | struct drm_framebuffer *fb = | ||
608 | container_of(kref, struct drm_framebuffer, base.refcount); | ||
609 | struct drm_device *dev = fb->dev; | ||
610 | |||
611 | /* | ||
612 | * The lookup idr holds a weak reference, which has not necessarily been | ||
613 | * removed at this point. Check for that. | ||
614 | */ | ||
615 | drm_mode_object_unregister(dev, &fb->base); | ||
616 | |||
617 | fb->funcs->destroy(fb); | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * drm_framebuffer_init - initialize a framebuffer | ||
622 | * @dev: DRM device | ||
623 | * @fb: framebuffer to be initialized | ||
624 | * @funcs: ... with these functions | ||
625 | * | ||
626 | * Allocates an ID for the framebuffer's parent mode object, sets its mode | ||
627 | * functions & device file and adds it to the master fd list. | ||
628 | * | ||
629 | * IMPORTANT: | ||
630 | * This functions publishes the fb and makes it available for concurrent access | ||
631 | * by other users. Which means by this point the fb _must_ be fully set up - | ||
632 | * since all the fb attributes are invariant over its lifetime, no further | ||
633 | * locking but only correct reference counting is required. | ||
634 | * | ||
635 | * Returns: | ||
636 | * Zero on success, error code on failure. | ||
637 | */ | ||
638 | int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | ||
639 | const struct drm_framebuffer_funcs *funcs) | ||
640 | { | ||
641 | int ret; | ||
642 | |||
643 | INIT_LIST_HEAD(&fb->filp_head); | ||
644 | fb->dev = dev; | ||
645 | fb->funcs = funcs; | ||
646 | |||
647 | ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, | ||
648 | false, drm_framebuffer_free); | ||
649 | if (ret) | ||
650 | goto out; | ||
651 | |||
652 | mutex_lock(&dev->mode_config.fb_lock); | ||
653 | dev->mode_config.num_fb++; | ||
654 | list_add(&fb->head, &dev->mode_config.fb_list); | ||
655 | mutex_unlock(&dev->mode_config.fb_lock); | ||
656 | |||
657 | drm_mode_object_register(dev, &fb->base); | ||
658 | out: | ||
659 | return ret; | ||
660 | } | ||
661 | EXPORT_SYMBOL(drm_framebuffer_init); | ||
662 | |||
663 | /** | ||
664 | * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference | ||
665 | * @dev: drm device | ||
666 | * @id: id of the fb object | ||
667 | * | ||
668 | * If successful, this grabs an additional reference to the framebuffer - | ||
669 | * callers need to make sure to eventually unreference the returned framebuffer | ||
670 | * again, using @drm_framebuffer_unreference. | ||
671 | */ | ||
672 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
673 | uint32_t id) | ||
674 | { | ||
675 | struct drm_mode_object *obj; | ||
676 | struct drm_framebuffer *fb = NULL; | ||
677 | |||
678 | obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_FB); | ||
679 | if (obj) | ||
680 | fb = obj_to_fb(obj); | ||
681 | return fb; | ||
682 | } | ||
683 | EXPORT_SYMBOL(drm_framebuffer_lookup); | ||
684 | |||
685 | /** | ||
686 | * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr | ||
687 | * @fb: fb to unregister | ||
688 | * | ||
689 | * Drivers need to call this when cleaning up driver-private framebuffers, e.g. | ||
690 | * those used for fbdev. Note that the caller must hold a reference of it's own, | ||
691 | * i.e. the object may not be destroyed through this call (since it'll lead to a | ||
692 | * locking inversion). | ||
693 | */ | ||
694 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) | ||
695 | { | ||
696 | struct drm_device *dev; | ||
697 | |||
698 | if (!fb) | ||
699 | return; | ||
700 | |||
701 | dev = fb->dev; | ||
702 | |||
703 | /* Mark fb as reaped and drop idr ref. */ | ||
704 | drm_mode_object_unregister(dev, &fb->base); | ||
705 | } | ||
706 | EXPORT_SYMBOL(drm_framebuffer_unregister_private); | ||
707 | |||
708 | /** | ||
709 | * drm_framebuffer_cleanup - remove a framebuffer object | ||
710 | * @fb: framebuffer to remove | ||
711 | * | ||
712 | * Cleanup framebuffer. This function is intended to be used from the drivers | ||
713 | * ->destroy callback. It can also be used to clean up driver private | ||
714 | * framebuffers embedded into a larger structure. | ||
715 | * | ||
716 | * Note that this function does not remove the fb from active usuage - if it is | ||
717 | * still used anywhere, hilarity can ensue since userspace could call getfb on | ||
718 | * the id and get back -EINVAL. Obviously no concern at driver unload time. | ||
719 | * | ||
720 | * Also, the framebuffer will not be removed from the lookup idr - for | ||
721 | * user-created framebuffers this will happen in in the rmfb ioctl. For | ||
722 | * driver-private objects (e.g. for fbdev) drivers need to explicitly call | ||
723 | * drm_framebuffer_unregister_private. | ||
724 | */ | ||
725 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | ||
726 | { | ||
727 | struct drm_device *dev = fb->dev; | ||
728 | |||
729 | mutex_lock(&dev->mode_config.fb_lock); | ||
730 | list_del(&fb->head); | ||
731 | dev->mode_config.num_fb--; | ||
732 | mutex_unlock(&dev->mode_config.fb_lock); | ||
733 | } | ||
734 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | ||
735 | |||
736 | /** | ||
737 | * drm_framebuffer_remove - remove and unreference a framebuffer object | ||
738 | * @fb: framebuffer to remove | ||
739 | * | ||
740 | * Scans all the CRTCs and planes in @dev's mode_config. If they're | ||
741 | * using @fb, removes it, setting it to NULL. Then drops the reference to the | ||
742 | * passed-in framebuffer. Might take the modeset locks. | ||
743 | * | ||
744 | * Note that this function optimizes the cleanup away if the caller holds the | ||
745 | * last reference to the framebuffer. It is also guaranteed to not take the | ||
746 | * modeset locks in this case. | ||
747 | */ | ||
748 | void drm_framebuffer_remove(struct drm_framebuffer *fb) | ||
749 | { | ||
750 | struct drm_device *dev; | ||
751 | struct drm_crtc *crtc; | ||
752 | struct drm_plane *plane; | ||
753 | |||
754 | if (!fb) | ||
755 | return; | ||
756 | |||
757 | dev = fb->dev; | ||
758 | |||
759 | WARN_ON(!list_empty(&fb->filp_head)); | ||
760 | |||
761 | /* | ||
762 | * drm ABI mandates that we remove any deleted framebuffers from active | ||
763 | * useage. But since most sane clients only remove framebuffers they no | ||
764 | * longer need, try to optimize this away. | ||
765 | * | ||
766 | * Since we're holding a reference ourselves, observing a refcount of 1 | ||
767 | * means that we're the last holder and can skip it. Also, the refcount | ||
768 | * can never increase from 1 again, so we don't need any barriers or | ||
769 | * locks. | ||
770 | * | ||
771 | * Note that userspace could try to race with use and instate a new | ||
772 | * usage _after_ we've cleared all current ones. End result will be an | ||
773 | * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot | ||
774 | * in this manner. | ||
775 | */ | ||
776 | if (drm_framebuffer_read_refcount(fb) > 1) { | ||
777 | drm_modeset_lock_all(dev); | ||
778 | /* remove from any CRTC */ | ||
779 | drm_for_each_crtc(crtc, dev) { | ||
780 | if (crtc->primary->fb == fb) { | ||
781 | /* should turn off the crtc */ | ||
782 | if (drm_crtc_force_disable(crtc)) | ||
783 | DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); | ||
784 | } | ||
785 | } | ||
786 | |||
787 | drm_for_each_plane(plane, dev) { | ||
788 | if (plane->fb == fb) | ||
789 | drm_plane_force_disable(plane); | ||
790 | } | ||
791 | drm_modeset_unlock_all(dev); | ||
792 | } | ||
793 | |||
794 | drm_framebuffer_unreference(fb); | ||
795 | } | ||
796 | EXPORT_SYMBOL(drm_framebuffer_remove); | ||
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5a7809f029ba..0119161cad57 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -36,10 +36,12 @@ | |||
36 | #include <uapi/drm/drm_fourcc.h> | 36 | #include <uapi/drm/drm_fourcc.h> |
37 | #include <drm/drm_modeset_lock.h> | 37 | #include <drm/drm_modeset_lock.h> |
38 | #include <drm/drm_rect.h> | 38 | #include <drm/drm_rect.h> |
39 | #include <drm/drm_modeset.h> | ||
40 | #include <drm/drm_framebuffer.h> | ||
41 | #include <drm/drm_modes.h> | ||
39 | 42 | ||
40 | struct drm_device; | 43 | struct drm_device; |
41 | struct drm_mode_set; | 44 | struct drm_mode_set; |
42 | struct drm_framebuffer; | ||
43 | struct drm_object_properties; | 45 | struct drm_object_properties; |
44 | struct drm_file; | 46 | struct drm_file; |
45 | struct drm_clip_rect; | 47 | struct drm_clip_rect; |
@@ -47,14 +49,6 @@ struct device_node; | |||
47 | struct fence; | 49 | struct fence; |
48 | struct edid; | 50 | struct edid; |
49 | 51 | ||
50 | struct drm_mode_object { | ||
51 | uint32_t id; | ||
52 | uint32_t type; | ||
53 | struct drm_object_properties *properties; | ||
54 | struct kref refcount; | ||
55 | void (*free_cb)(struct kref *kref); | ||
56 | }; | ||
57 | |||
58 | #define DRM_OBJECT_MAX_PROPERTY 24 | 52 | #define DRM_OBJECT_MAX_PROPERTY 24 |
59 | struct drm_object_properties { | 53 | struct drm_object_properties { |
60 | int count, atomic_count; | 54 | int count, atomic_count; |
@@ -94,15 +88,6 @@ static inline uint64_t I642U64(int64_t val) | |||
94 | #define DRM_REFLECT_Y BIT(5) | 88 | #define DRM_REFLECT_Y BIT(5) |
95 | #define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) | 89 | #define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) |
96 | 90 | ||
97 | enum drm_connector_force { | ||
98 | DRM_FORCE_UNSPECIFIED, | ||
99 | DRM_FORCE_OFF, | ||
100 | DRM_FORCE_ON, /* force on analog part normally */ | ||
101 | DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ | ||
102 | }; | ||
103 | |||
104 | #include <drm/drm_modes.h> | ||
105 | |||
106 | enum drm_connector_status { | 91 | enum drm_connector_status { |
107 | connector_status_connected = 1, | 92 | connector_status_connected = 1, |
108 | connector_status_disconnected = 2, | 93 | connector_status_disconnected = 2, |
@@ -166,101 +151,6 @@ struct drm_tile_group { | |||
166 | u8 group_data[8]; | 151 | u8 group_data[8]; |
167 | }; | 152 | }; |
168 | 153 | ||
169 | /** | ||
170 | * struct drm_framebuffer_funcs - framebuffer hooks | ||
171 | */ | ||
172 | struct drm_framebuffer_funcs { | ||
173 | /** | ||
174 | * @destroy: | ||
175 | * | ||
176 | * Clean up framebuffer resources, specifically also unreference the | ||
177 | * backing storage. The core guarantees to call this function for every | ||
178 | * framebuffer successfully created by ->fb_create() in | ||
179 | * &drm_mode_config_funcs. Drivers must also call | ||
180 | * drm_framebuffer_cleanup() to release DRM core resources for this | ||
181 | * framebuffer. | ||
182 | */ | ||
183 | void (*destroy)(struct drm_framebuffer *framebuffer); | ||
184 | |||
185 | /** | ||
186 | * @create_handle: | ||
187 | * | ||
188 | * Create a buffer handle in the driver-specific buffer manager (either | ||
189 | * GEM or TTM) valid for the passed-in struct &drm_file. This is used by | ||
190 | * the core to implement the GETFB IOCTL, which returns (for | ||
191 | * sufficiently priviledged user) also a native buffer handle. This can | ||
192 | * be used for seamless transitions between modesetting clients by | ||
193 | * copying the current screen contents to a private buffer and blending | ||
194 | * between that and the new contents. | ||
195 | * | ||
196 | * GEM based drivers should call drm_gem_handle_create() to create the | ||
197 | * handle. | ||
198 | * | ||
199 | * RETURNS: | ||
200 | * | ||
201 | * 0 on success or a negative error code on failure. | ||
202 | */ | ||
203 | int (*create_handle)(struct drm_framebuffer *fb, | ||
204 | struct drm_file *file_priv, | ||
205 | unsigned int *handle); | ||
206 | /** | ||
207 | * @dirty: | ||
208 | * | ||
209 | * Optional callback for the dirty fb IOCTL. | ||
210 | * | ||
211 | * Userspace can notify the driver via this callback that an area of the | ||
212 | * framebuffer has changed and should be flushed to the display | ||
213 | * hardware. This can also be used internally, e.g. by the fbdev | ||
214 | * emulation, though that's not the case currently. | ||
215 | * | ||
216 | * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd | ||
217 | * for more information as all the semantics and arguments have a one to | ||
218 | * one mapping on this function. | ||
219 | * | ||
220 | * RETURNS: | ||
221 | * | ||
222 | * 0 on success or a negative error code on failure. | ||
223 | */ | ||
224 | int (*dirty)(struct drm_framebuffer *framebuffer, | ||
225 | struct drm_file *file_priv, unsigned flags, | ||
226 | unsigned color, struct drm_clip_rect *clips, | ||
227 | unsigned num_clips); | ||
228 | }; | ||
229 | |||
230 | struct drm_framebuffer { | ||
231 | struct drm_device *dev; | ||
232 | /* | ||
233 | * Note that the fb is refcounted for the benefit of driver internals, | ||
234 | * for example some hw, disabling a CRTC/plane is asynchronous, and | ||
235 | * scanout does not actually complete until the next vblank. So some | ||
236 | * cleanup (like releasing the reference(s) on the backing GEM bo(s)) | ||
237 | * should be deferred. In cases like this, the driver would like to | ||
238 | * hold a ref to the fb even though it has already been removed from | ||
239 | * userspace perspective. | ||
240 | * The refcount is stored inside the mode object. | ||
241 | */ | ||
242 | /* | ||
243 | * Place on the dev->mode_config.fb_list, access protected by | ||
244 | * dev->mode_config.fb_lock. | ||
245 | */ | ||
246 | struct list_head head; | ||
247 | struct drm_mode_object base; | ||
248 | const struct drm_framebuffer_funcs *funcs; | ||
249 | unsigned int pitches[4]; | ||
250 | unsigned int offsets[4]; | ||
251 | uint64_t modifier[4]; | ||
252 | unsigned int width; | ||
253 | unsigned int height; | ||
254 | /* depth can be 15 or 16 */ | ||
255 | unsigned int depth; | ||
256 | int bits_per_pixel; | ||
257 | int flags; | ||
258 | uint32_t pixel_format; /* fourcc format */ | ||
259 | int hot_x; | ||
260 | int hot_y; | ||
261 | struct list_head filp_head; | ||
262 | }; | ||
263 | |||
264 | struct drm_property_blob { | 154 | struct drm_property_blob { |
265 | struct drm_mode_object base; | 155 | struct drm_mode_object base; |
266 | struct drm_device *dev; | 156 | struct drm_device *dev; |
@@ -2888,14 +2778,6 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj, | |||
2888 | extern int drm_object_property_get_value(struct drm_mode_object *obj, | 2778 | extern int drm_object_property_get_value(struct drm_mode_object *obj, |
2889 | struct drm_property *property, | 2779 | struct drm_property *property, |
2890 | uint64_t *value); | 2780 | uint64_t *value); |
2891 | extern int drm_framebuffer_init(struct drm_device *dev, | ||
2892 | struct drm_framebuffer *fb, | ||
2893 | const struct drm_framebuffer_funcs *funcs); | ||
2894 | extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
2895 | uint32_t id); | ||
2896 | extern void drm_framebuffer_remove(struct drm_framebuffer *fb); | ||
2897 | extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); | ||
2898 | extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); | ||
2899 | 2781 | ||
2900 | extern void drm_object_attach_property(struct drm_mode_object *obj, | 2782 | extern void drm_object_attach_property(struct drm_mode_object *obj, |
2901 | struct drm_property *property, | 2783 | struct drm_property *property, |
@@ -2976,11 +2858,6 @@ int drm_plane_create_zpos_immutable_property(struct drm_plane *plane, | |||
2976 | unsigned int zpos); | 2858 | unsigned int zpos); |
2977 | 2859 | ||
2978 | /* Helpers */ | 2860 | /* Helpers */ |
2979 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
2980 | uint32_t id, uint32_t type); | ||
2981 | void drm_mode_object_reference(struct drm_mode_object *obj); | ||
2982 | void drm_mode_object_unreference(struct drm_mode_object *obj); | ||
2983 | |||
2984 | static inline struct drm_plane *drm_plane_find(struct drm_device *dev, | 2861 | static inline struct drm_plane *drm_plane_find(struct drm_device *dev, |
2985 | uint32_t id) | 2862 | uint32_t id) |
2986 | { | 2863 | { |
@@ -3049,39 +2926,6 @@ static inline uint32_t drm_color_lut_extract(uint32_t user_input, | |||
3049 | } | 2926 | } |
3050 | 2927 | ||
3051 | /** | 2928 | /** |
3052 | * drm_framebuffer_reference - incr the fb refcnt | ||
3053 | * @fb: framebuffer | ||
3054 | * | ||
3055 | * This functions increments the fb's refcount. | ||
3056 | */ | ||
3057 | static inline void drm_framebuffer_reference(struct drm_framebuffer *fb) | ||
3058 | { | ||
3059 | drm_mode_object_reference(&fb->base); | ||
3060 | } | ||
3061 | |||
3062 | /** | ||
3063 | * drm_framebuffer_unreference - unref a framebuffer | ||
3064 | * @fb: framebuffer to unref | ||
3065 | * | ||
3066 | * This functions decrements the fb's refcount and frees it if it drops to zero. | ||
3067 | */ | ||
3068 | static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb) | ||
3069 | { | ||
3070 | drm_mode_object_unreference(&fb->base); | ||
3071 | } | ||
3072 | |||
3073 | /** | ||
3074 | * drm_framebuffer_read_refcount - read the framebuffer reference count. | ||
3075 | * @fb: framebuffer | ||
3076 | * | ||
3077 | * This functions returns the framebuffer's reference count. | ||
3078 | */ | ||
3079 | static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) | ||
3080 | { | ||
3081 | return atomic_read(&fb->base.refcount.refcount); | ||
3082 | } | ||
3083 | |||
3084 | /** | ||
3085 | * drm_connector_reference - incr the connector refcnt | 2929 | * drm_connector_reference - incr the connector refcnt |
3086 | * @connector: connector | 2930 | * @connector: connector |
3087 | * | 2931 | * |
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h new file mode 100644 index 000000000000..46abdace8fa5 --- /dev/null +++ b/include/drm/drm_framebuffer.h | |||
@@ -0,0 +1,170 @@ | |||
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 | #ifndef __DRM_FRAMEBUFFER_H__ | ||
24 | #define __DRM_FRAMEBUFFER_H__ | ||
25 | |||
26 | #include <linux/list.h> | ||
27 | #include <linux/ctype.h> | ||
28 | #include <drm/drm_modeset.h> | ||
29 | |||
30 | struct drm_framebuffer; | ||
31 | struct drm_file; | ||
32 | struct drm_device; | ||
33 | |||
34 | /** | ||
35 | * struct drm_framebuffer_funcs - framebuffer hooks | ||
36 | */ | ||
37 | struct drm_framebuffer_funcs { | ||
38 | /** | ||
39 | * @destroy: | ||
40 | * | ||
41 | * Clean up framebuffer resources, specifically also unreference the | ||
42 | * backing storage. The core guarantees to call this function for every | ||
43 | * framebuffer successfully created by ->fb_create() in | ||
44 | * &drm_mode_config_funcs. Drivers must also call | ||
45 | * drm_framebuffer_cleanup() to release DRM core resources for this | ||
46 | * framebuffer. | ||
47 | */ | ||
48 | void (*destroy)(struct drm_framebuffer *framebuffer); | ||
49 | |||
50 | /** | ||
51 | * @create_handle: | ||
52 | * | ||
53 | * Create a buffer handle in the driver-specific buffer manager (either | ||
54 | * GEM or TTM) valid for the passed-in struct &drm_file. This is used by | ||
55 | * the core to implement the GETFB IOCTL, which returns (for | ||
56 | * sufficiently priviledged user) also a native buffer handle. This can | ||
57 | * be used for seamless transitions between modesetting clients by | ||
58 | * copying the current screen contents to a private buffer and blending | ||
59 | * between that and the new contents. | ||
60 | * | ||
61 | * GEM based drivers should call drm_gem_handle_create() to create the | ||
62 | * handle. | ||
63 | * | ||
64 | * RETURNS: | ||
65 | * | ||
66 | * 0 on success or a negative error code on failure. | ||
67 | */ | ||
68 | int (*create_handle)(struct drm_framebuffer *fb, | ||
69 | struct drm_file *file_priv, | ||
70 | unsigned int *handle); | ||
71 | /** | ||
72 | * @dirty: | ||
73 | * | ||
74 | * Optional callback for the dirty fb IOCTL. | ||
75 | * | ||
76 | * Userspace can notify the driver via this callback that an area of the | ||
77 | * framebuffer has changed and should be flushed to the display | ||
78 | * hardware. This can also be used internally, e.g. by the fbdev | ||
79 | * emulation, though that's not the case currently. | ||
80 | * | ||
81 | * See documentation in drm_mode.h for the struct drm_mode_fb_dirty_cmd | ||
82 | * for more information as all the semantics and arguments have a one to | ||
83 | * one mapping on this function. | ||
84 | * | ||
85 | * RETURNS: | ||
86 | * | ||
87 | * 0 on success or a negative error code on failure. | ||
88 | */ | ||
89 | int (*dirty)(struct drm_framebuffer *framebuffer, | ||
90 | struct drm_file *file_priv, unsigned flags, | ||
91 | unsigned color, struct drm_clip_rect *clips, | ||
92 | unsigned num_clips); | ||
93 | }; | ||
94 | |||
95 | struct drm_framebuffer { | ||
96 | struct drm_device *dev; | ||
97 | /* | ||
98 | * Note that the fb is refcounted for the benefit of driver internals, | ||
99 | * for example some hw, disabling a CRTC/plane is asynchronous, and | ||
100 | * scanout does not actually complete until the next vblank. So some | ||
101 | * cleanup (like releasing the reference(s) on the backing GEM bo(s)) | ||
102 | * should be deferred. In cases like this, the driver would like to | ||
103 | * hold a ref to the fb even though it has already been removed from | ||
104 | * userspace perspective. | ||
105 | * The refcount is stored inside the mode object. | ||
106 | */ | ||
107 | /* | ||
108 | * Place on the dev->mode_config.fb_list, access protected by | ||
109 | * dev->mode_config.fb_lock. | ||
110 | */ | ||
111 | struct list_head head; | ||
112 | struct drm_mode_object base; | ||
113 | const struct drm_framebuffer_funcs *funcs; | ||
114 | unsigned int pitches[4]; | ||
115 | unsigned int offsets[4]; | ||
116 | uint64_t modifier[4]; | ||
117 | unsigned int width; | ||
118 | unsigned int height; | ||
119 | /* depth can be 15 or 16 */ | ||
120 | unsigned int depth; | ||
121 | int bits_per_pixel; | ||
122 | int flags; | ||
123 | uint32_t pixel_format; /* fourcc format */ | ||
124 | int hot_x; | ||
125 | int hot_y; | ||
126 | struct list_head filp_head; | ||
127 | }; | ||
128 | |||
129 | int drm_framebuffer_init(struct drm_device *dev, | ||
130 | struct drm_framebuffer *fb, | ||
131 | const struct drm_framebuffer_funcs *funcs); | ||
132 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||
133 | uint32_t id); | ||
134 | void drm_framebuffer_remove(struct drm_framebuffer *fb); | ||
135 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb); | ||
136 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); | ||
137 | |||
138 | /** | ||
139 | * drm_framebuffer_reference - incr the fb refcnt | ||
140 | * @fb: framebuffer | ||
141 | * | ||
142 | * This functions increments the fb's refcount. | ||
143 | */ | ||
144 | static inline void drm_framebuffer_reference(struct drm_framebuffer *fb) | ||
145 | { | ||
146 | drm_mode_object_reference(&fb->base); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * drm_framebuffer_unreference - unref a framebuffer | ||
151 | * @fb: framebuffer to unref | ||
152 | * | ||
153 | * This functions decrements the fb's refcount and frees it if it drops to zero. | ||
154 | */ | ||
155 | static inline void drm_framebuffer_unreference(struct drm_framebuffer *fb) | ||
156 | { | ||
157 | drm_mode_object_unreference(&fb->base); | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * drm_framebuffer_read_refcount - read the framebuffer reference count. | ||
162 | * @fb: framebuffer | ||
163 | * | ||
164 | * This functions returns the framebuffer's reference count. | ||
165 | */ | ||
166 | static inline uint32_t drm_framebuffer_read_refcount(struct drm_framebuffer *fb) | ||
167 | { | ||
168 | return atomic_read(&fb->base.refcount.refcount); | ||
169 | } | ||
170 | #endif | ||
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 48e1a56ea283..fed9fe81590c 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #ifndef __DRM_MODES_H__ | 27 | #ifndef __DRM_MODES_H__ |
28 | #define __DRM_MODES_H__ | 28 | #define __DRM_MODES_H__ |
29 | 29 | ||
30 | #include <drm/drm_modeset.h> | ||
31 | |||
30 | /* | 32 | /* |
31 | * Note on terminology: here, for brevity and convenience, we refer to connector | 33 | * Note on terminology: here, for brevity and convenience, we refer to connector |
32 | * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, | 34 | * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, |
diff --git a/include/drm/drm_modeset.h b/include/drm/drm_modeset.h new file mode 100644 index 000000000000..0c2b0f3c5f34 --- /dev/null +++ b/include/drm/drm_modeset.h | |||
@@ -0,0 +1,50 @@ | |||
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 | #ifndef __DRM_MODESET_H__ | ||
24 | #define __DRM_MODESET_H__ | ||
25 | |||
26 | #include <linux/kref.h> | ||
27 | struct drm_object_properties; | ||
28 | |||
29 | struct drm_mode_object { | ||
30 | uint32_t id; | ||
31 | uint32_t type; | ||
32 | struct drm_object_properties *properties; | ||
33 | struct kref refcount; | ||
34 | void (*free_cb)(struct kref *kref); | ||
35 | }; | ||
36 | |||
37 | struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, | ||
38 | uint32_t id, uint32_t type); | ||
39 | void drm_mode_object_reference(struct drm_mode_object *obj); | ||
40 | void drm_mode_object_unreference(struct drm_mode_object *obj); | ||
41 | |||
42 | /* FIXME: This is temporary until we have a drm_connector.h */ | ||
43 | enum drm_connector_force { | ||
44 | DRM_FORCE_UNSPECIFIED, | ||
45 | DRM_FORCE_OFF, | ||
46 | DRM_FORCE_ON, /* force on analog part normally */ | ||
47 | DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ | ||
48 | }; | ||
49 | |||
50 | #endif | ||