From 0fea2ed61e7fc5f31520cf2476f33bdf2d6756ab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:24 +0100 Subject: [PATCH 01/55] drm/amdgpu: Remove call to reservation_object_test_signaled_rcu before wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since fence_wait_timeout_reservation_object_wait_timeout_rcu() with a timeout of 0 becomes reservation_object_test_signaled_rcu(), we do not need to handle such conversion in the caller. The only challenge are those callers that wish to differentiate the error code between the nonblocking busy check and potentially blocking wait. Signed-off-by: Chris Wilson Cc: Alex Deucher Cc: Christian König Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index a7ea9a3b454e..e0171c75b60c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -407,10 +407,8 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_amdgpu_bo(gobj); - if (timeout == 0) - ret = reservation_object_test_signaled_rcu(robj->tbo.resv, true); - else - ret = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, timeout); + ret = reservation_object_wait_timeout_rcu(robj->tbo.resv, true, true, + timeout); /* ret == 0 means not signaled, * ret > 0 means signaled From cd34db4a526c370fa0ca21b046b3a2636c481f56 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:25 +0100 Subject: [PATCH 02/55] drm/etnaviv: Remove manual call to reservation_object_test_signaled_rcu before wait Since fence_wait_timeout_reservation_object_wait_timeout_rcu() with a timeout of 0 becomes reservation_object_test_signaled_rcu(), we do not need to handle such conversion in the caller. The only challenge are those callers that wish to differentiate the error code between the nonblocking busy check and potentially blocking wait. Signed-off-by: Chris Wilson Cc: Lucas Stach Cc: Russell King Cc: Christian Gmeiner Reviewed-by: Daniel Vetter Acked-by: Lucas Stach Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 5ce3603e6eac..9ffca2478e02 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -409,20 +409,16 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op, struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); struct drm_device *dev = obj->dev; bool write = !!(op & ETNA_PREP_WRITE); - int ret; + unsigned long remain = + op & ETNA_PREP_NOSYNC ? 0 : etnaviv_timeout_to_jiffies(timeout); + long lret; - if (op & ETNA_PREP_NOSYNC) { - if (!reservation_object_test_signaled_rcu(etnaviv_obj->resv, - write)) - return -EBUSY; - } else { - unsigned long remain = etnaviv_timeout_to_jiffies(timeout); - - ret = reservation_object_wait_timeout_rcu(etnaviv_obj->resv, - write, true, remain); - if (ret <= 0) - return ret == 0 ? -ETIMEDOUT : ret; - } + lret = reservation_object_wait_timeout_rcu(etnaviv_obj->resv, + write, true, remain); + if (lret < 0) + return lret; + else if (lret == 0) + return remain == 0 ? -EBUSY : -ETIMEDOUT; if (etnaviv_obj->flags & ETNA_BO_CACHED) { if (!etnaviv_obj->sgt) { From 491d8a1dd8bea5fb8295af006d44b543053e65c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:27 +0100 Subject: [PATCH 03/55] drm/nouveau: Remove call to reservation_object_test_signaled_rcu before wait Since fence_wait_timeout_reservation_object_wait_timeout_rcu() with a timeout of 0 becomes reservation_object_test_signaled_rcu(), we do not need to handle such conversion in the caller. The only challenge are those callers that wish to differentiate the error code between the nonblocking busy check and potentially blocking wait. Signed-off-by: Chris Wilson Cc: Ben Skeggs Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-4-chris@chris-wilson.co.uk --- drivers/gpu/drm/nouveau/nouveau_gem.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 72e2399bce39..0bd7164bc817 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -861,6 +861,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, struct nouveau_bo *nvbo; bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); bool write = !!(req->flags & NOUVEAU_GEM_CPU_PREP_WRITE); + long lret; int ret; gem = drm_gem_object_lookup(file_priv, req->handle); @@ -868,19 +869,15 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, return -ENOENT; nvbo = nouveau_gem_object(gem); - if (no_wait) - ret = reservation_object_test_signaled_rcu(nvbo->bo.resv, write) ? 0 : -EBUSY; - else { - long lret; + lret = reservation_object_wait_timeout_rcu(nvbo->bo.resv, write, true, + no_wait ? 0 : 30 * HZ); + if (!lret) + ret = -EBUSY; + else if (lret > 0) + ret = 0; + else + ret = lret; - lret = reservation_object_wait_timeout_rcu(nvbo->bo.resv, write, true, 30 * HZ); - if (!lret) - ret = -EBUSY; - else if (lret > 0) - ret = 0; - else - ret = lret; - } nouveau_bo_sync_for_cpu(nvbo); drm_gem_object_unreference_unlocked(gem); From 998a7aa1bdeb10e06e4ac7bff533145339fa1256 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:28 +0100 Subject: [PATCH 04/55] drm/vmwgfx: Remove call to reservation_object_test_signaled_rcu before wait Since fence_wait_timeout_reservation_object_wait_timeout_rcu() with a timeout of 0 becomes reservation_object_test_signaled_rcu(), we do not need to handle such conversion in the caller. The only challenge are those callers that wish to differentiate the error code between the nonblocking busy check and potentially blocking wait. Signed-off-by: Chris Wilson Cc: Sinclair Yeh Cc: Thomas Hellstrom Reviewed-by: Sinclair Yeh Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-5-chris@chris-wilson.co.uk --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6a328d507a28..1a85fb2d4dc6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -574,10 +574,8 @@ static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo, bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); long lret; - if (nonblock) - return reservation_object_test_signaled_rcu(bo->resv, true) ? 0 : -EBUSY; - - lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, MAX_SCHEDULE_TIMEOUT); + lret = reservation_object_wait_timeout_rcu(bo->resv, true, true, + nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); if (!lret) return -EBUSY; else if (lret < 0) From 4be0542073a33cc063b6a8f8fb367536e234e7aa Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:29 +0100 Subject: [PATCH 05/55] dma-buf: Introduce fence_get_rcu_safe() This variant of fence_get_rcu() takes an RCU protected pointer to a fence and carefully returns a reference to the fence ensuring that it is not reallocated as it does. This is required when mixing fences and SLAB_DESTROY_BY_RCU - although it serves a more pedagogical function atm Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Sumit Semwal Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-6-chris@chris-wilson.co.uk --- include/linux/fence.h | 56 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/include/linux/fence.h b/include/linux/fence.h index 0d763053f97a..c9c5ba98c302 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h @@ -182,6 +182,16 @@ void fence_init(struct fence *fence, const struct fence_ops *ops, void fence_release(struct kref *kref); void fence_free(struct fence *fence); +/** + * fence_put - decreases refcount of the fence + * @fence: [in] fence to reduce refcount of + */ +static inline void fence_put(struct fence *fence) +{ + if (fence) + kref_put(&fence->refcount, fence_release); +} + /** * fence_get - increases refcount of the fence * @fence: [in] fence to increase refcount of @@ -210,13 +220,49 @@ static inline struct fence *fence_get_rcu(struct fence *fence) } /** - * fence_put - decreases refcount of the fence - * @fence: [in] fence to reduce refcount of + * fence_get_rcu_safe - acquire a reference to an RCU tracked fence + * @fence: [in] pointer to fence to increase refcount of + * + * Function returns NULL if no refcount could be obtained, or the fence. + * This function handles acquiring a reference to a fence that may be + * reallocated within the RCU grace period (such as with SLAB_DESTROY_BY_RCU), + * so long as the caller is using RCU on the pointer to the fence. + * + * An alternative mechanism is to employ a seqlock to protect a bunch of + * fences, such as used by struct reservation_object. When using a seqlock, + * the seqlock must be taken before and checked after a reference to the + * fence is acquired (as shown here). + * + * The caller is required to hold the RCU read lock. */ -static inline void fence_put(struct fence *fence) +static inline struct fence *fence_get_rcu_safe(struct fence * __rcu *fencep) { - if (fence) - kref_put(&fence->refcount, fence_release); + do { + struct fence *fence; + + fence = rcu_dereference(*fencep); + if (!fence || !fence_get_rcu(fence)) + return NULL; + + /* The atomic_inc_not_zero() inside fence_get_rcu() + * provides a full memory barrier upon success (such as now). + * This is paired with the write barrier from assigning + * to the __rcu protected fence pointer so that if that + * pointer still matches the current fence, we know we + * have successfully acquire a reference to it. If it no + * longer matches, we are holding a reference to some other + * reallocated pointer. This is possible if the allocator + * is using a freelist like SLAB_DESTROY_BY_RCU where the + * fence remains valid for the RCU grace period, but it + * may be reallocated. When using such allocators, we are + * responsible for ensuring the reference we get is to + * the right fence, as below. + */ + if (fence == rcu_access_pointer(*fencep)) + return rcu_pointer_handoff(fence); + + fence_put(fence); + } while (1); } int fence_signal(struct fence *fence); From fedf54132d2410c3949036e3f611ab8dd9dbe89e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:30 +0100 Subject: [PATCH 06/55] dma-buf: Restart reservation_object_get_fences_rcu() after writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to be completely generic, we have to double check the read seqlock after acquiring a reference to the fence. If the driver is allocating fences from a SLAB_DESTROY_BY_RCU, or similar freelist, then within an RCU grace period a fence may be freed and reallocated. The RCU read side critical section does not prevent this reallocation, instead we have to inspect the reservation's seqlock to double check if the fences have been reassigned as we were acquiring our reference. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Christian König Cc: Alex Deucher Cc: Sumit Semwal Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-7-chris@chris-wilson.co.uk --- drivers/dma-buf/reservation.c | 71 +++++++++++++++-------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 723d8af988e5..ba3e25dab95b 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -280,18 +280,24 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, unsigned *pshared_count, struct fence ***pshared) { - unsigned shared_count = 0; - unsigned retry = 1; - struct fence **shared = NULL, *fence_excl = NULL; - int ret = 0; + struct fence **shared = NULL; + struct fence *fence_excl; + unsigned int shared_count; + int ret = 1; - while (retry) { + do { struct reservation_object_list *fobj; unsigned seq; + unsigned int i; - seq = read_seqcount_begin(&obj->seq); + shared_count = i = 0; rcu_read_lock(); + seq = read_seqcount_begin(&obj->seq); + + fence_excl = rcu_dereference(obj->fence_excl); + if (fence_excl && !fence_get_rcu(fence_excl)) + goto unlock; fobj = rcu_dereference(obj->fence); if (fobj) { @@ -309,52 +315,37 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, } ret = -ENOMEM; - shared_count = 0; break; } shared = nshared; - memcpy(shared, fobj->shared, sz); shared_count = fobj->shared_count; - } else - shared_count = 0; - fence_excl = rcu_dereference(obj->fence_excl); - - retry = read_seqcount_retry(&obj->seq, seq); - if (retry) - goto unlock; - - if (!fence_excl || fence_get_rcu(fence_excl)) { - unsigned i; for (i = 0; i < shared_count; ++i) { - if (fence_get_rcu(shared[i])) - continue; - - /* uh oh, refcount failed, abort and retry */ - while (i--) - fence_put(shared[i]); - - if (fence_excl) { - fence_put(fence_excl); - fence_excl = NULL; - } - - retry = 1; - break; + shared[i] = rcu_dereference(fobj->shared[i]); + if (!fence_get_rcu(shared[i])) + break; } - } else - retry = 1; + } + if (i != shared_count || read_seqcount_retry(&obj->seq, seq)) { + while (i--) + fence_put(shared[i]); + fence_put(fence_excl); + goto unlock; + } + + ret = 0; unlock: rcu_read_unlock(); - } - *pshared_count = shared_count; - if (shared_count) - *pshared = shared; - else { - *pshared = NULL; + } while (ret); + + if (!shared_count) { kfree(shared); + shared = NULL; } + + *pshared_count = shared_count; + *pshared = shared; *pfence_excl = fence_excl; return ret; From 1cec20f0ea0e3bc617aed47e0936f17386c131f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:31 +0100 Subject: [PATCH 07/55] dma-buf: Restart reservation_object_wait_timeout_rcu() after writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to be completely generic, we have to double check the read seqlock after acquiring a reference to the fence. If the driver is allocating fences from a SLAB_DESTROY_BY_RCU, or similar freelist, then within an RCU grace period a fence may be freed and reallocated. The RCU read side critical section does not prevent this reallocation, instead we have to inspect the reservation's seqlock to double check if the fences have been reassigned as we were acquiring our reference. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Christian König Cc: Alex Deucher Cc: Sumit Semwal Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-8-chris@chris-wilson.co.uk --- drivers/dma-buf/reservation.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index ba3e25dab95b..648e5d0325f9 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -388,9 +388,6 @@ retry: if (fobj) shared_count = fobj->shared_count; - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - for (i = 0; i < shared_count; ++i) { struct fence *lfence = rcu_dereference(fobj->shared[i]); @@ -413,9 +410,6 @@ retry: if (!shared_count) { struct fence *fence_excl = rcu_dereference(obj->fence_excl); - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - if (fence_excl && !test_bit(FENCE_FLAG_SIGNALED_BIT, &fence_excl->flags)) { if (!fence_get_rcu(fence_excl)) @@ -430,6 +424,11 @@ retry: rcu_read_unlock(); if (fence) { + if (read_seqcount_retry(&obj->seq, seq)) { + fence_put(fence); + goto retry; + } + ret = fence_wait_timeout(fence, intr, ret); fence_put(fence); if (ret > 0 && wait_all && (i + 1 < shared_count)) From b68d8379c28ddfe74b78be9414082f281332d86c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 29 Aug 2016 08:08:32 +0100 Subject: [PATCH 08/55] dma-buf: Restart reservation_object_test_signaled_rcu() after writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to be completely generic, we have to double check the read seqlock after acquiring a reference to the fence. If the driver is allocating fences from a SLAB_DESTROY_BY_RCU, or similar freelist, then within an RCU grace period a fence may be freed and reallocated. The RCU read side critical section does not prevent this reallocation, instead we have to inspect the reservation's seqlock to double check if the fences have been reassigned as we were acquiring our reference. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Maarten Lankhorst Cc: Christian König Cc: Alex Deucher Cc: Sumit Semwal Cc: linux-media@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: linaro-mm-sig@lists.linaro.org Reviewed-by: Daniel Vetter Signed-off-by: Sumit Semwal Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-9-chris@chris-wilson.co.uk --- drivers/dma-buf/reservation.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 648e5d0325f9..82de59f7cbbd 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -474,12 +474,13 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj, bool test_all) { unsigned seq, shared_count; - int ret = true; + int ret; + rcu_read_lock(); retry: + ret = true; shared_count = 0; seq = read_seqcount_begin(&obj->seq); - rcu_read_lock(); if (test_all) { unsigned i; @@ -490,46 +491,35 @@ retry: if (fobj) shared_count = fobj->shared_count; - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - for (i = 0; i < shared_count; ++i) { struct fence *fence = rcu_dereference(fobj->shared[i]); ret = reservation_object_test_signaled_single(fence); if (ret < 0) - goto unlock_retry; + goto retry; else if (!ret) break; } - /* - * There could be a read_seqcount_retry here, but nothing cares - * about whether it's the old or newer fence pointers that are - * signaled. That race could still have happened after checking - * read_seqcount_retry. If you care, use ww_mutex_lock. - */ + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; } if (!shared_count) { struct fence *fence_excl = rcu_dereference(obj->fence_excl); - if (read_seqcount_retry(&obj->seq, seq)) - goto unlock_retry; - if (fence_excl) { ret = reservation_object_test_signaled_single( fence_excl); if (ret < 0) - goto unlock_retry; + goto retry; + + if (read_seqcount_retry(&obj->seq, seq)) + goto retry; } } rcu_read_unlock(); return ret; - -unlock_retry: - rcu_read_unlock(); - goto retry; } EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu); From 024b6a63138c1e6988927f9a90b6b43b8d4fe6f5 Mon Sep 17 00:00:00 2001 From: Shyam Saini Date: Mon, 10 Oct 2016 04:37:16 +0530 Subject: [PATCH 09/55] gpu: drm: gma500: Use vma_pages() Replace explicit computation of vma page count by a call to vma_pages() Signed-off-by: Shyam Saini Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476054436-9378-1-git-send-email-mayhs11saini@gmail.com --- drivers/gpu/drm/gma500/framebuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 3a44e705db53..0fde8503607c 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -124,7 +124,7 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + psbfb->gtt->offset; - page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + page_num = vma_pages(vma); address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); From 9c9a7f94840f50324c9abab547ad224272c822fa Mon Sep 17 00:00:00 2001 From: Jiang Biao Date: Tue, 11 Oct 2016 14:03:45 +0800 Subject: [PATCH 10/55] drm/gma500: remove useless comment Remove useless comment in framebuffer.c. Signed-off-by: Jiang Biao Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476165825-12137-1-git-send-email-jiang.biao2@zte.com.cn --- drivers/gpu/drm/gma500/framebuffer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 0fde8503607c..aee2f9733457 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -298,7 +298,6 @@ static struct drm_framebuffer *psb_framebuffer_create * psbfb_alloc - allocate frame buffer memory * @dev: the DRM device * @aligned_size: space needed - * @force: fall back to GEM buffers if need be * * Allocate the frame buffer. In the usual case we get a GTT range that * is stolen memory backed and life is simple. If there isn't sufficient From 1550333c597a98fc1bb529167ecf22333a3b4b39 Mon Sep 17 00:00:00 2001 From: Jiang Biao Date: Wed, 12 Oct 2016 10:18:19 +0800 Subject: [PATCH 11/55] drm/gma500: add comments for new parameters Added comments for new parameters. Signed-off-by: Jiang Biao Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476238699-25820-1-git-send-email-jiang.biao2@zte.com.cn --- drivers/gpu/drm/gma500/gtt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 8f69225ce2b4..76aea2e7fb9d 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -76,6 +76,7 @@ static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) * psb_gtt_insert - put an object into the GTT * @dev: our DRM device * @r: our GTT range + * @resume: on resume * * Take our preallocated GTT range and insert the GEM object into * the GTT. This is protected via the gtt mutex which the caller @@ -321,6 +322,7 @@ out: * @len: length (bytes) of address space required * @name: resource name * @backed: resource should be backed by stolen pages + * @align: requested alignment * * Ask the kernel core to find us a suitable range of addresses * to use for a GTT mapping. From f7741aa75e76440f4e9ecfe512feebe9bce33ca8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 12 Oct 2016 09:22:27 +0300 Subject: [PATCH 12/55] drm/savage: dereferencing an error pointer A recent cleanup changed the kmalloc() + copy_from_user() to memdup_user() but the error handling wasn't updated so we might call kfree(-EFAULT) and crash. Fixes: a6e3918bcdb1 ('GPU-DRM-Savage: Use memdup_user() rather than duplicating') Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161012062227.GU12841@mwanda --- drivers/gpu/drm/savage/savage_state.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index 3dc0d8ff95ec..2db89bed52e8 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -1004,6 +1004,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ kvb_addr = memdup_user(cmdbuf->vb_addr, cmdbuf->vb_size); if (IS_ERR(kvb_addr)) { ret = PTR_ERR(kvb_addr); + kvb_addr = NULL; goto done; } cmdbuf->vb_addr = kvb_addr; From d807ed1c55fb1b2dcfb2bc49385e227f6bee7669 Mon Sep 17 00:00:00 2001 From: Brian Starkey Date: Thu, 13 Oct 2016 10:47:08 +0100 Subject: [PATCH 13/55] drm: atomic: Clarify documentation around drm_atomic_crtc_needs_modeset Add some additional comments to more explicitly describe the meaning and usage of the three CRTC modeset detection booleans: mode_changed, connectors_changed and active_changed. Suggested-by: Daniel Vetter Signed-off-by: Brian Starkey Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476352028-16701-1-git-send-email-brian.starkey@arm.com --- drivers/gpu/drm/drm_atomic_helper.c | 9 +++++---- include/drm/drm_atomic.h | 11 ++++++++++- include/drm/drm_crtc.h | 5 +++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3f83476f996..36f83fe5ec46 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -458,10 +458,11 @@ mode_fixup(struct drm_atomic_state *state) * removed from the crtc. * crtc_state->active_changed is set when crtc_state->active changes, * which is used for dpms. + * See also: drm_atomic_crtc_needs_modeset() * * IMPORTANT: * - * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a + * Drivers which set ->mode_changed (e.g. in their ->atomic_check hooks if a * plane update can't be done without a full modeset) _must_ call this function * afterwards after that change. It is permitted to call this function multiple * times for the same update, e.g. when the ->atomic_check functions depend upon @@ -510,9 +511,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, for_each_connector_in_state(state, connector, connector_state, i) { /* - * This only sets crtc->mode_changed for routing changes, - * drivers must set crtc->mode_changed themselves when connector - * properties need to be updated. + * This only sets crtc->connectors_changed for routing changes, + * drivers must set crtc->connectors_changed themselves when + * connector properties need to be updated. */ ret = update_connector_routing(state, connector, connector_state); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 9701f2dfb784..c52f99415c55 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -365,8 +365,17 @@ int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); * * To give drivers flexibility struct &drm_crtc_state has 3 booleans to track * whether the state CRTC changed enough to need a full modeset cycle: - * connectors_changed, mode_changed and active_change. This helper simply + * connectors_changed, mode_changed and active_changed. This helper simply * combines these three to compute the overall need for a modeset for @state. + * + * The atomic helper code sets these booleans, but drivers can and should + * change them appropriately to accurately represent whether a modeset is + * really needed. In general, drivers should avoid full modesets whenever + * possible. + * + * For example if the CRTC mode has changed, and the hardware is able to enact + * the requested mode change without going through a full modeset, the driver + * should clear mode_changed during its ->atomic_check. */ static inline bool drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0aa292526567..92246619947c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -116,6 +116,11 @@ struct drm_plane_helper_funcs; * never return in a failure from the ->atomic_check callback. Userspace assumes * that a DPMS On will always succeed. In other words: @enable controls resource * assignment, @active controls the actual hardware state. + * + * The three booleans active_changed, connectors_changed and mode_changed are + * intended to indicate whether a full modeset is needed, rather than strictly + * describing what has changed in a commit. + * See also: drm_atomic_crtc_needs_modeset() */ struct drm_crtc_state { struct drm_crtc *crtc; From 1dfdb0ed34b28b086ffc1f9fb9f538ab60298029 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 13 Oct 2016 10:38:11 +0200 Subject: [PATCH 14/55] drm/crtc: constify drm_crtc_mask parameter Now that drm_crtc_index takes a const, the same can be done for drm_crtc_mask. Signed-off-by: Maarten Lankhorst Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/6e32d013-6fee-34ad-f8d2-59139f3dc4c1@linux.intel.com --- include/drm/drm_crtc.h | 2 +- include/drm/drm_encoder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 92246619947c..4633915cb51b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1359,7 +1359,7 @@ static inline unsigned int drm_crtc_index(const struct drm_crtc *crtc) * Given a registered CRTC, return the mask bit of that CRTC for an * encoder's possible_crtcs field. */ -static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc) +static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) { return 1 << drm_crtc_index(crtc); } diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index 387e33a4d6ee..c7438ff0d609 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -189,7 +189,7 @@ static inline unsigned int drm_encoder_index(struct drm_encoder *encoder) } /* FIXME: We have an include file mess still, drm_crtc.h needs untangling. */ -static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc); +static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc); /** * drm_encoder_crtc_ok - can a given crtc drive a given encoder? From 0853695c3ba46f97dfc0b5885f7b7e640ca212dd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 14 Oct 2016 13:18:18 +0100 Subject: [PATCH 15/55] drm: Add reference counting to drm_atomic_state drm_atomic_state has a complicated single owner model that tracks the single reference from allocation through to destruction on another thread - or perhaps on a local error path. We can simplify this tracking by using reference counting (at a cost of a few more atomics). This is even more beneficial when the lifetime of the state becomes more convoluted than being passed to a single worker thread for the commit. v2: Double check !intel atomic_commit functions for missing gets v3: Update kerneldocs Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Reviewed-by: Eric Engestrom Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161014121833.439-27-chris@chris-wilson.co.uk --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 3 +- drivers/gpu/drm/drm_atomic.c | 25 ++--- drivers/gpu/drm/drm_atomic_helper.c | 98 +++++--------------- drivers/gpu/drm/drm_fb_helper.c | 9 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 3 +- drivers/gpu/drm/i915/i915_debugfs.c | 5 +- drivers/gpu/drm/i915/intel_display.c | 31 +++---- drivers/gpu/drm/i915/intel_sprite.c | 4 +- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +- drivers/gpu/drm/msm/msm_atomic.c | 3 +- drivers/gpu/drm/omapdrm/omap_drv.c | 3 +- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 3 +- drivers/gpu/drm/sti/sti_drv.c | 3 +- drivers/gpu/drm/tegra/drm.c | 3 +- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 - drivers/gpu/drm/vc4/vc4_kms.c | 3 +- include/drm/drm_atomic.h | 31 ++++++- include/drm/drm_plane.h | 1 - 18 files changed, 102 insertions(+), 131 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 5f484310bee9..9f6222895212 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -464,7 +464,7 @@ atmel_hlcdc_dc_atomic_complete(struct atmel_hlcdc_dc_commit *commit) drm_atomic_helper_cleanup_planes(dev, old_state); - drm_atomic_state_free(old_state); + drm_atomic_state_put(old_state); /* Complete the commit, wake up any waiter. */ spin_lock(&dc->commit.wait.lock); @@ -521,6 +521,7 @@ static int atmel_hlcdc_dc_atomic_commit(struct drm_device *dev, /* Swap the state, this is the point of no return. */ drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (async) queue_work(dc->wq, &commit->work); else diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 23739609427d..5dd70540219c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -74,6 +74,8 @@ EXPORT_SYMBOL(drm_atomic_state_default_release); int drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state) { + kref_init(&state->ref); + /* TODO legacy paths should maybe do a better job about * setting this appropriately? */ @@ -215,22 +217,16 @@ void drm_atomic_state_clear(struct drm_atomic_state *state) EXPORT_SYMBOL(drm_atomic_state_clear); /** - * drm_atomic_state_free - free all memory for an atomic state - * @state: atomic state to deallocate + * __drm_atomic_state_free - free all memory for an atomic state + * @ref: This atomic state to deallocate * * This frees all memory associated with an atomic state, including all the * per-object state for planes, crtcs and connectors. */ -void drm_atomic_state_free(struct drm_atomic_state *state) +void __drm_atomic_state_free(struct kref *ref) { - struct drm_device *dev; - struct drm_mode_config *config; - - if (!state) - return; - - dev = state->dev; - config = &dev->mode_config; + struct drm_atomic_state *state = container_of(ref, typeof(*state), ref); + struct drm_mode_config *config = &state->dev->mode_config; drm_atomic_state_clear(state); @@ -243,7 +239,7 @@ void drm_atomic_state_free(struct drm_atomic_state *state) kfree(state); } } -EXPORT_SYMBOL(drm_atomic_state_free); +EXPORT_SYMBOL(__drm_atomic_state_free); /** * drm_atomic_get_crtc_state - get crtc state @@ -1742,7 +1738,7 @@ retry: if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { /* * Unlike commit, check_only does not clean up state. - * Below we call drm_atomic_state_free for it. + * Below we call drm_atomic_state_put for it. */ ret = drm_atomic_check_only(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { @@ -1775,8 +1771,7 @@ out: goto retry; } - if (ret || arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) - drm_atomic_state_free(state); + drm_atomic_state_put(state); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 36f83fe5ec46..07b432f43b98 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1208,7 +1208,7 @@ static void commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_cleanup_done(state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); } static void commit_work(struct work_struct *work) @@ -1290,6 +1290,7 @@ int drm_atomic_helper_commit(struct drm_device *dev, * make sure work items don't artifically stall on each another. */ + drm_atomic_state_get(state); if (nonblock) queue_work(system_unbound_wq, &state->commit_work); else @@ -1591,7 +1592,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done); * * This signals completion of the atomic update @state, including any cleanup * work. If used, it must be called right before calling - * drm_atomic_state_free(). + * drm_atomic_state_put(). * * This is part of the atomic helper support for nonblocking commits, see * drm_atomic_helper_setup_commit() for an overview. @@ -2114,18 +2115,13 @@ retry: state->legacy_cursor_update = true; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2187,18 +2183,13 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2327,18 +2318,13 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2480,11 +2466,8 @@ int drm_atomic_helper_disable_all(struct drm_device *dev, } err = drm_atomic_commit(state); - free: - if (err < 0) - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return err; } EXPORT_SYMBOL(drm_atomic_helper_disable_all); @@ -2535,7 +2518,7 @@ retry: err = drm_atomic_helper_disable_all(dev, &ctx); if (err < 0) { - drm_atomic_state_free(state); + drm_atomic_state_put(state); state = ERR_PTR(err); goto unlock; } @@ -2624,18 +2607,13 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2684,18 +2662,13 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2744,18 +2717,13 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2828,18 +2796,13 @@ retry: } ret = drm_atomic_nonblocking_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -2915,19 +2878,14 @@ retry: crtc_state->active = active; ret = drm_atomic_commit(state); - if (ret != 0) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - return 0; fail: if (ret == -EDEADLK) goto backoff; connector->dpms = old_mode; - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); @@ -3334,7 +3292,7 @@ drm_atomic_helper_duplicate_state(struct drm_device *dev, free: if (err < 0) { - drm_atomic_state_free(state); + drm_atomic_state_put(state); state = ERR_PTR(err); } @@ -3449,22 +3407,14 @@ retry: goto fail; ret = drm_atomic_commit(state); - if (ret) - goto fail; - - /* Driver takes ownership of state on successful commit. */ - - drm_property_unreference_blob(blob); - - return 0; fail: if (ret == -EDEADLK) goto backoff; - drm_atomic_state_free(state); + drm_atomic_state_put(state); drm_property_unreference_blob(blob); - return ret; + backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 03414bde1f15..22d4f0e22101 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -367,9 +367,7 @@ fail: if (ret == -EDEADLK) goto backoff; - if (ret != 0) - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; backoff: @@ -1361,16 +1359,13 @@ retry: info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; - fail: drm_atomic_clean_old_fb(dev, plane_mask, ret); if (ret == -EDEADLK) goto backoff; - if (ret != 0) - drm_atomic_state_free(state); - + drm_atomic_state_put(state); return ret; backoff: diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index def78c8c1780..4a21a745c373 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -69,7 +69,7 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); spin_lock(&priv->lock); priv->pending &= ~commit->crtcs; @@ -254,6 +254,7 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (nonblock) schedule_work(&commit->work); else diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 27b0e34dadec..6c7bb87f764e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3941,10 +3941,9 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_i915_private *dev_priv, ret = drm_atomic_commit(state); out: - drm_modeset_unlock_all(dev); WARN(ret, "Toggling workaround to %i returns %i\n", enable, ret); - if (ret) - drm_atomic_state_free(state); + drm_modeset_unlock_all(dev); + drm_atomic_state_put(state); } static int ivb_pipe_crc_ctl_reg(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ad8d712ae84c..a12e093c54cf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3582,7 +3582,7 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv) return; err: - drm_atomic_state_free(state); + drm_atomic_state_put(state); } void intel_finish_reset(struct drm_i915_private *dev_priv) @@ -3643,6 +3643,8 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) intel_hpd_init(dev_priv); } + if (state) + drm_atomic_state_put(state); drm_modeset_drop_locks(ctx); drm_modeset_acquire_fini(ctx); mutex_unlock(&dev->mode_config.mutex); @@ -6882,7 +6884,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) dev_priv->display.crtc_disable(crtc_state, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); DRM_DEBUG_KMS("[CRTC:%d:%s] hw state adjusted, was enabled, now disabled\n", crtc->base.id, crtc->name); @@ -11249,8 +11251,8 @@ found: return true; fail: - drm_atomic_state_free(state); - drm_atomic_state_free(restore_state); + drm_atomic_state_put(state); + drm_atomic_state_put(restore_state); restore_state = state = NULL; if (ret == -EDEADLK) { @@ -11279,10 +11281,9 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, return; ret = drm_atomic_commit(state); - if (ret) { + if (ret) DRM_DEBUG_KMS("Couldn't release load detect pipe: %i\n", ret); - drm_atomic_state_free(state); - } + drm_atomic_state_put(state); } static int i9xx_pll_refclk(struct drm_device *dev, @@ -12350,8 +12351,7 @@ retry: goto retry; } - if (ret) - drm_atomic_state_free(state); + drm_atomic_state_put(state); if (ret == 0 && event) { spin_lock_irq(&dev->event_lock); @@ -14437,7 +14437,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_cleanup_done(state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); /* As one of the primary mmio accessors, KMS has a high likelihood * of triggering bugs in unclaimed access. After we finish @@ -14520,6 +14520,7 @@ static int intel_atomic_commit(struct drm_device *dev, intel_shared_dpll_commit(state); intel_atomic_track_fbs(state); + drm_atomic_state_get(state); if (nonblock) queue_work(system_unbound_wq, &state->commit_work); else @@ -14561,9 +14562,8 @@ retry: goto retry; } - if (ret) out: - drm_atomic_state_free(state); + drm_atomic_state_put(state); } /* @@ -16305,8 +16305,8 @@ retry: dev_priv->display.optimize_watermarks(cs); } - drm_atomic_state_free(state); fail: + drm_atomic_state_put(state); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); } @@ -16943,10 +16943,9 @@ void intel_display_resume(struct drm_device *dev) drm_modeset_acquire_fini(&ctx); mutex_unlock(&dev->mode_config.mutex); - if (ret) { + if (ret) DRM_ERROR("Restoring old state failed with %i\n", ret); - drm_atomic_state_free(state); - } + drm_atomic_state_put(state); } void intel_modeset_gem_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 73a521fdf1bd..be3e04623e2a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -987,9 +987,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, drm_modeset_backoff(&ctx); } - if (ret) - drm_atomic_state_free(state); - + drm_atomic_state_put(state); out: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index cf83f6507ec8..db61aa5f32ef 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -83,7 +83,7 @@ static void mtk_atomic_complete(struct mtk_drm_private *private, drm_atomic_helper_wait_for_vblanks(drm, state); drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); } static void mtk_atomic_work(struct work_struct *work) @@ -110,6 +110,7 @@ static int mtk_atomic_commit(struct drm_device *drm, drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (async) mtk_atomic_schedule(private, state); else diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 73bae382eac3..db193f835298 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -141,7 +141,7 @@ static void complete_commit(struct msm_commit *c, bool async) kms->funcs->complete_commit(kms, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); commit_destroy(c); } @@ -256,6 +256,7 @@ int msm_atomic_commit(struct drm_device *dev, * current layout. */ + drm_atomic_state_get(state); if (nonblock) { queue_work(priv->atomic_wq, &c->work); return 0; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index e1cfba51cff6..1735c7accf72 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -105,7 +105,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) dispc_runtime_put(); - drm_atomic_state_free(old_state); + drm_atomic_state_put(old_state); /* Complete the commit, wake up any waiter. */ spin_lock(&priv->commit.lock); @@ -176,6 +176,7 @@ static int omap_atomic_commit(struct drm_device *dev, /* Swap the state, this is the point of no return. */ drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (nonblock) schedule_work(&commit->work); else diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index bd9c3bb9252c..c76ed9ee6a01 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -264,7 +264,7 @@ static void rcar_du_atomic_complete(struct rcar_du_commit *commit) drm_atomic_helper_cleanup_planes(dev, old_state); - drm_atomic_state_free(old_state); + drm_atomic_state_put(old_state); /* Complete the commit, wake up any waiter. */ spin_lock(&rcdu->commit.wait.lock); @@ -330,6 +330,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev, /* Swap the state, this is the point of no return. */ drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (nonblock) schedule_work(&commit->work); else diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 2784919a7366..7087499969bc 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -184,7 +184,7 @@ static void sti_atomic_complete(struct sti_private *private, drm_atomic_helper_wait_for_vblanks(drm, state); drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); } static void sti_atomic_work(struct work_struct *work) @@ -217,6 +217,7 @@ static int sti_atomic_commit(struct drm_device *drm, drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (nonblock) sti_atomic_schedule(private, state); else diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 8ab47b502d83..a9630c2d6cb3 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -63,7 +63,7 @@ static void tegra_atomic_complete(struct tegra_drm *tegra, drm_atomic_helper_wait_for_vblanks(drm, state); drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); } static void tegra_atomic_work(struct work_struct *work) @@ -96,6 +96,7 @@ static int tegra_atomic_commit(struct drm_device *drm, drm_atomic_helper_swap_state(state, true); + drm_atomic_state_get(state); if (nonblock) tegra_atomic_schedule(tegra, state); else diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index a694977c32f4..147fb28287ae 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -143,8 +143,6 @@ static int tilcdc_commit(struct drm_device *dev, drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - return 0; } diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index c1f65c6c8e60..f31f72af8551 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -61,7 +61,7 @@ vc4_atomic_complete_commit(struct vc4_commit *c) drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); + drm_atomic_state_put(state); up(&vc4->async_modeset); @@ -173,6 +173,7 @@ static int vc4_atomic_commit(struct drm_device *dev, * current layout. */ + drm_atomic_state_get(state); if (nonblock) { vc4_queue_seqno_cb(dev, &c->cb, wait_seqno, vc4_atomic_complete_commit_seqno_cb); diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index c52f99415c55..fc8af53b18aa 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -153,6 +153,7 @@ struct __drm_connnectors_state { /** * struct drm_atomic_state - the global state object for atomic updates + * @ref: count of all references to this state (will not be freed until zero) * @dev: parent DRM device * @allow_modeset: allow full modeset * @legacy_cursor_update: hint to enforce legacy cursor IOCTL semantics @@ -164,6 +165,8 @@ struct __drm_connnectors_state { * @acquire_ctx: acquire context for this atomic modeset state update */ struct drm_atomic_state { + struct kref ref; + struct drm_device *dev; bool allow_modeset : 1; bool legacy_cursor_update : 1; @@ -193,7 +196,33 @@ static inline void drm_crtc_commit_get(struct drm_crtc_commit *commit) struct drm_atomic_state * __must_check drm_atomic_state_alloc(struct drm_device *dev); void drm_atomic_state_clear(struct drm_atomic_state *state); -void drm_atomic_state_free(struct drm_atomic_state *state); + +/** + * drm_atomic_state_get - acquire a reference to the atomic state + * @state: The atomic state + * + * Returns a new reference to the @state + */ +static inline struct drm_atomic_state * +drm_atomic_state_get(struct drm_atomic_state *state) +{ + kref_get(&state->ref); + return state; +} + +void __drm_atomic_state_free(struct kref *ref); + +/** + * drm_atomic_state_put - release a reference to the atomic state + * @state: The atomic state + * + * This releases a reference to @state which is freed after removing the + * final reference. No locking required and callable from any context. + */ +static inline void drm_atomic_state_put(struct drm_atomic_state *state) +{ + kref_put(&state->ref, __drm_atomic_state_free); +} int __must_check drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 43cf193e54d6..02353904cdba 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -88,7 +88,6 @@ struct drm_plane_state { struct drm_atomic_state *state; }; - /** * struct drm_plane_funcs - driver plane control functions */ From 49521b13cbc02aff9ac1fff8d425055cc86cef08 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 14 Oct 2016 15:22:22 +0200 Subject: [PATCH 16/55] drivers/gpu/vga: allocate vga_arb_write() buffer on stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Size of kmalloc() in vga_arb_write() is controlled by user. Too large kmalloc() size triggers WARNING message on console. Allocate the buffer on stack to avoid the WARNING. The string must be small (e.g "target PCI:domain:bus:dev.fn"). Signed-off-by: Dmitry Vyukov Reviewed-by: Ville Syrjälä Cc: Dave Airlie Cc: Ville Syrjälä Cc: dri-devel@lists.freedesktop.org Cc: syzkaller@googlegroups.com Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476451342-146510-1-git-send-email-dvyukov@google.com --- drivers/gpu/vga/vgaarb.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 1887f199ccb7..77657a8c0cd4 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1022,21 +1022,16 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, unsigned int io_state; - char *kbuf, *curr_pos; + char kbuf[64], *curr_pos; size_t remaining = count; int ret_val; int i; - - kbuf = kmalloc(count + 1, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - - if (copy_from_user(kbuf, buf, count)) { - kfree(kbuf); + if (count >= sizeof(kbuf)) + return -EINVAL; + if (copy_from_user(kbuf, buf, count)) return -EFAULT; - } curr_pos = kbuf; kbuf[count] = '\0'; /* Just to make sure... */ @@ -1259,11 +1254,9 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf, goto done; } /* If we got here, the message written is not part of the protocol! */ - kfree(kbuf); return -EPROTO; done: - kfree(kbuf); return ret_val; } From 876f43c073d79ad3f14a4cebd1aea1f39fc4daf5 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Mon, 17 Oct 2016 17:34:37 +0530 Subject: [PATCH 17/55] drm: add picture aspect ratio flags This patch adds drm flag bits for aspect ratio information Currently drm flag bits don't have field for mode's picture aspect ratio. This field will help the driver to pick mode with right aspect ratio, and help in setting right VIC field in avi infoframes. V2: Addressed review comments from Sean - Changed PAR-> PIC_AR V3: Rebase V3: Added r-b by Jose Signed-off-by: Shashank Sharma Reviewed-by: Jim Bride Reviewed-by: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476705880-15600-2-git-send-email-shashank.sharma@intel.com --- include/uapi/drm/drm_mode.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index df0e3504c349..5c142b1387ac 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -77,6 +77,19 @@ extern "C" { #define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) #define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) +/* Picture aspect ratio options */ +#define DRM_MODE_PICTURE_ASPECT_NONE 0 +#define DRM_MODE_PICTURE_ASPECT_4_3 1 +#define DRM_MODE_PICTURE_ASPECT_16_9 2 + +/* Aspect ratio flag bitmask (4 bits 22:19) */ +#define DRM_MODE_FLAG_PIC_AR_MASK (0x0F<<19) +#define DRM_MODE_FLAG_PIC_AR_NONE \ + (DRM_MODE_PICTURE_ASPECT_NONE<<19) +#define DRM_MODE_FLAG_PIC_AR_4_3 \ + (DRM_MODE_PICTURE_ASPECT_4_3<<19) +#define DRM_MODE_FLAG_PIC_AR_16_9 \ + (DRM_MODE_PICTURE_ASPECT_16_9<<19) /* DPMS flags */ /* bit compatible with the xorg definitions. */ @@ -92,11 +105,6 @@ extern "C" { #define DRM_MODE_SCALE_CENTER 2 /* Centered, no scaling */ #define DRM_MODE_SCALE_ASPECT 3 /* Full screen, preserve aspect */ -/* Picture aspect ratio options */ -#define DRM_MODE_PICTURE_ASPECT_NONE 0 -#define DRM_MODE_PICTURE_ASPECT_4_3 1 -#define DRM_MODE_PICTURE_ASPECT_16_9 2 - /* Dithering mode options */ #define DRM_MODE_DITHERING_OFF 0 #define DRM_MODE_DITHERING_ON 1 From 6dffd431e2296cda08e7e4f0242e02df1d1698cd Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Mon, 17 Oct 2016 17:34:38 +0530 Subject: [PATCH 18/55] drm: Add aspect ratio parsing in DRM layer Current DRM layer functions don't parse aspect ratio information while converting a user mode->kernel mode or vice versa. This causes modeset to pick mode with wrong aspect ratio, eventually causing failures in HDMI compliance test cases, due to wrong VIC. This patch adds aspect ratio information in DRM's mode conversion and mode comparision functions, to make sure kernel picks mode with right aspect ratio (as per the VIC). V2: Addressed review comments from Sean: - Fix spellings/typo - No need to handle aspect ratio none - Add a break, for default case too V3: Rebase V4: Added r-b from Jose Signed-off-by: Shashank Sharma Signed-off-by: Lin, Jia Signed-off-by: Akashdeep Sharma Reviewed-by: Jim Bride Reviewed-by: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476705880-15600-3-git-send-email-shashank.sharma@intel.com --- drivers/gpu/drm/drm_modes.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 53f07ac7c174..fde927a6cc5d 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -997,6 +997,7 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, mode1->vsync_end == mode2->vsync_end && mode1->vtotal == mode2->vtotal && mode1->vscan == mode2->vscan && + mode1->picture_aspect_ratio == mode2->picture_aspect_ratio && (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) == (mode2->flags & ~DRM_MODE_FLAG_3D_MASK)) return true; @@ -1499,6 +1500,21 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, out->vrefresh = in->vrefresh; out->flags = in->flags; out->type = in->type; + out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; + + switch (in->picture_aspect_ratio) { + case HDMI_PICTURE_ASPECT_4_3: + out->flags |= DRM_MODE_FLAG_PIC_AR_4_3; + break; + case HDMI_PICTURE_ASPECT_16_9: + out->flags |= DRM_MODE_FLAG_PIC_AR_16_9; + break; + case HDMI_PICTURE_ASPECT_RESERVED: + default: + out->flags |= DRM_MODE_FLAG_PIC_AR_NONE; + break; + } + strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -1544,6 +1560,21 @@ int drm_mode_convert_umode(struct drm_display_mode *out, strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; + /* Clearing picture aspect ratio bits from out flags */ + out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; + + switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) { + case DRM_MODE_FLAG_PIC_AR_4_3: + out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_4_3; + break; + case DRM_MODE_FLAG_PIC_AR_16_9: + out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9; + break; + default: + out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; + break; + } + out->status = drm_mode_validate_basic(out); if (out->status != MODE_OK) goto out; From a6e78b3e1406575323b30b65890ee3c29930fb27 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Mon, 17 Oct 2016 17:34:39 +0530 Subject: [PATCH 19/55] video: Add new aspect ratios for HDMI 2.0 HDMI 2.0/CEA-861-F introduces two new aspect ratios: - 64:27 - 256:135 This patch adds enumeration for the new aspect ratios in the existing aspect ratio list. V2: rebase V3: rebase V4: Added r-b from Jose, Ack by Tomi Signed-off-by: Shashank Sharma Reviewed-by: Sean Paul Reviewed-by: Jose Abreu Acked-by: Tomi Valkeinen Cc: Daniel Vetter Cc: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476705880-15600-4-git-send-email-shashank.sharma@intel.com --- drivers/video/hdmi.c | 4 ++++ include/linux/hdmi.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 162689227a23..1cf907ecded4 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -533,6 +533,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect) return "4:3"; case HDMI_PICTURE_ASPECT_16_9: return "16:9"; + case HDMI_PICTURE_ASPECT_64_27: + return "64:27"; + case HDMI_PICTURE_ASPECT_256_135: + return "256:135"; case HDMI_PICTURE_ASPECT_RESERVED: return "Reserved"; } diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index e9744202fa29..edbb4fc674ed 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -78,6 +78,8 @@ enum hdmi_picture_aspect { HDMI_PICTURE_ASPECT_NONE, HDMI_PICTURE_ASPECT_4_3, HDMI_PICTURE_ASPECT_16_9, + HDMI_PICTURE_ASPECT_64_27, + HDMI_PICTURE_ASPECT_256_135, HDMI_PICTURE_ASPECT_RESERVED, }; From a68362fe3e84fcbedd49939aa200519aa5410135 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Mon, 17 Oct 2016 17:34:40 +0530 Subject: [PATCH 20/55] drm: Add and handle new aspect ratios in DRM layer HDMI 2.0/CEA-861-F introduces two new aspect ratios: - 64:27 - 256:135 This patch: - Adds new DRM flags for to represent these new aspect ratios. - Adds new cases to handle these aspect ratios while converting from user->kernel mode or vise versa. V2: Rebase V3: Align macro for DRM_MODE_PICTURE_ASPECT_256_135 (Jim Bride) V4: Added r-b from Jose. Signed-off-by: Shashank Sharma Reviewed-by: Sean Paul Reviewed-by: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476705880-15600-5-git-send-email-shashank.sharma@intel.com --- drivers/gpu/drm/drm_modes.c | 12 ++++++++++++ include/uapi/drm/drm_mode.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index fde927a6cc5d..173b7d335834 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1509,6 +1509,12 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, case HDMI_PICTURE_ASPECT_16_9: out->flags |= DRM_MODE_FLAG_PIC_AR_16_9; break; + case HDMI_PICTURE_ASPECT_64_27: + out->flags |= DRM_MODE_FLAG_PIC_AR_64_27; + break; + case DRM_MODE_PICTURE_ASPECT_256_135: + out->flags |= DRM_MODE_FLAG_PIC_AR_256_135; + break; case HDMI_PICTURE_ASPECT_RESERVED: default: out->flags |= DRM_MODE_FLAG_PIC_AR_NONE; @@ -1570,6 +1576,12 @@ int drm_mode_convert_umode(struct drm_display_mode *out, case DRM_MODE_FLAG_PIC_AR_16_9: out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9; break; + case DRM_MODE_FLAG_PIC_AR_64_27: + out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_64_27; + break; + case DRM_MODE_FLAG_PIC_AR_256_135: + out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_256_135; + break; default: out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; break; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 5c142b1387ac..084b50a02dc5 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -81,6 +81,8 @@ extern "C" { #define DRM_MODE_PICTURE_ASPECT_NONE 0 #define DRM_MODE_PICTURE_ASPECT_4_3 1 #define DRM_MODE_PICTURE_ASPECT_16_9 2 +#define DRM_MODE_PICTURE_ASPECT_64_27 3 +#define DRM_MODE_PICTURE_ASPECT_256_135 4 /* Aspect ratio flag bitmask (4 bits 22:19) */ #define DRM_MODE_FLAG_PIC_AR_MASK (0x0F<<19) @@ -90,6 +92,10 @@ extern "C" { (DRM_MODE_PICTURE_ASPECT_4_3<<19) #define DRM_MODE_FLAG_PIC_AR_16_9 \ (DRM_MODE_PICTURE_ASPECT_16_9<<19) +#define DRM_MODE_FLAG_PIC_AR_64_27 \ + (DRM_MODE_PICTURE_ASPECT_64_27<<19) +#define DRM_MODE_FLAG_PIC_AR_256_135 \ + (DRM_MODE_PICTURE_ASPECT_256_135<<19) /* DPMS flags */ /* bit compatible with the xorg definitions. */ From f14f368670541bfa217573194027a58f2206e250 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 17 Oct 2016 09:35:12 +0100 Subject: [PATCH 21/55] drm/edid: Rename local variable block to edid The "block" variable points to the entire edid, not individual blocks despite it being named such. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161017083514.21772-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_edid.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index ec77bd3e1f08..3b4ac28f509e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1282,20 +1282,20 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, void *data) { int i, j = 0, valid_extensions = 0; - u8 *block, *new; + u8 *edid, *new; bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS); - if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) + if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL) return NULL; /* base block fetch */ for (i = 0; i < 4; i++) { - if (get_edid_block(data, block, 0, EDID_LENGTH)) + if (get_edid_block(data, edid, 0, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block, 0, print_bad_edid, + if (drm_edid_block_valid(edid, 0, print_bad_edid, &connector->edid_corrupt)) break; - if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { + if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) { connector->null_edid_counter++; goto carp; } @@ -1304,21 +1304,21 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, goto carp; /* if there's no extensions, we're done */ - if (block[0x7e] == 0) - return (struct edid *)block; + if (edid[0x7e] == 0) + return (struct edid *)edid; - new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); + new = krealloc(edid, (edid[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) goto out; - block = new; + edid = new; - for (j = 1; j <= block[0x7e]; j++) { + for (j = 1; j <= edid[0x7e]; j++) { for (i = 0; i < 4; i++) { if (get_edid_block(data, - block + (valid_extensions + 1) * EDID_LENGTH, + edid + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block + (valid_extensions + 1) + if (drm_edid_block_valid(edid + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid, NULL)) { @@ -1336,16 +1336,16 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, } } - if (valid_extensions != block[0x7e]) { - block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; - block[0x7e] = valid_extensions; - new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); + if (valid_extensions != edid[0x7e]) { + edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions; + edid[0x7e] = valid_extensions; + new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) goto out; - block = new; + edid = new; } - return (struct edid *)block; + return (struct edid *)edid; carp: if (print_bad_edid) { @@ -1355,7 +1355,7 @@ carp: connector->bad_edid_counter++; out: - kfree(block); + kfree(edid); return NULL; } EXPORT_SYMBOL_GPL(drm_do_get_edid); From a28187ccab9410cad20e8808f00cfc07f99649c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 17 Oct 2016 09:35:13 +0100 Subject: [PATCH 22/55] drm/edid: Use block local to refer to the block Now that we have the name "block" free once more, we can use it to point to the start of a block within the edid. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161017083514.21772-2-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_edid.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3b4ac28f509e..95de47ba1e77 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1313,15 +1313,13 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, edid = new; for (j = 1; j <= edid[0x7e]; j++) { + u8 *block = edid + (valid_extensions + 1) * EDID_LENGTH; + for (i = 0; i < 4; i++) { - if (get_edid_block(data, - edid + (valid_extensions + 1) * EDID_LENGTH, - j, EDID_LENGTH)) + if (get_edid_block(data, block, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(edid + (valid_extensions + 1) - * EDID_LENGTH, j, - print_bad_edid, - NULL)) { + if (drm_edid_block_valid(block, j, + print_bad_edid, NULL)) { valid_extensions++; break; } From 865afb11949e5bf4bb32d9a2aa9867c1ac4d8da0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 11 Oct 2016 16:15:04 -0700 Subject: [PATCH 23/55] drm/fb-helper: reject any changes to the fbdev The current fbdev emulation does not allow to push back changes in width, height or depth to KMS, hence reject any changes with an error. This makes sure that fbdev ioctl's fail properly and user space does not assume that changes succeeded. Signed-off-by: Stefan Agner Reviewed-by: Tomi Valkeinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161011231504.17688-1-stefan@agner.ch --- drivers/gpu/drm/drm_fb_helper.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 22d4f0e22101..8fffac8c5c75 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1209,11 +1209,14 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, if (var->pixclock != 0 || in_dbg_master()) return -EINVAL; - /* Need to resize the fb object !!! */ - if (var->bits_per_pixel > fb->bits_per_pixel || - var->xres > fb->width || var->yres > fb->height || - var->xres_virtual > fb->width || var->yres_virtual > fb->height) { - DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " + /* + * Changes struct fb_var_screeninfo are currently not pushed back + * to KMS, hence fail if different settings are requested. + */ + if (var->bits_per_pixel != fb->bits_per_pixel || + var->xres != fb->width || var->yres != fb->height || + var->xres_virtual != fb->width || var->yres_virtual != fb->height) { + DRM_DEBUG("fb userspace requested width/height/bpp different than current fb " "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual, From 9edbf1fa600a2ef17c7553c2103d0055d0320d15 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 6 Oct 2016 17:21:06 +0200 Subject: [PATCH 24/55] drm: Add API for capturing frame CRCs Adds files and directories to debugfs for controlling and reading frame CRCs, per CRTC: dri/0/crtc-0/crc dri/0/crtc-0/crc/control dri/0/crtc-0/crc/data Drivers can implement the set_crc_source callback() in drm_crtc_funcs to start and stop generating frame CRCs and can add entries to the output by calling drm_crtc_add_crc_entry. v2: - Lots of good fixes suggested by Thierry. - Added documentation. - Changed the debugfs layout. - Moved to allocate the entries circular queue once when frame generation gets enabled for the first time. v3: - Use the control file just to select the source, and start and stop capture when the data file is opened and closed, respectively. - Make variable the number of CRC values per entry, per source. - Allocate entries queue each time we start capturing as now there isn't a fixed number of CRC values per entry. - Store the frame counter in the data file as a 8-digit hex number. - For sources that cannot provide useful frame numbers, place XXXXXXXX in the frame field. v4: - Build only if CONFIG_DEBUG_FS is enabled. - Use memdup_user_nul. - Consolidate calculation of the size of an entry in a helper. - Add 0x prefix to hex numbers in the data file. - Remove unnecessary snprintf and strlen usage in read callback. v5: - Made the crcs array in drm_crtc_crc_entry fixed-size - Lots of other smaller improvements suggested by Emil Velikov v7: - Move definition of drm_debugfs_crtc_crc_add to drm_internal.h v8: - Call debugfs_remove_recursive when we fail to create the minor device v9: - Register the debugfs directory for a crtc from drm_crtc_register_all() v10: - Don't let debugfs failures interrupt CRTC registration (Emil Velikov) v11: - Remove extra brace that broke compilation. Sorry! Signed-off-by: Tomeu Vizoso Reviewed-by: Emil Velikov Acked-by: Benjamin Gaignard Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1475767268-14379-3-git-send-email-tomeu.vizoso@collabora.com --- Documentation/gpu/drm-uapi.rst | 6 + drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_crtc.c | 34 ++- drivers/gpu/drm/drm_debugfs.c | 34 ++- drivers/gpu/drm/drm_debugfs_crc.c | 351 ++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_internal.h | 16 ++ include/drm/drm_crtc.h | 41 ++++ include/drm/drm_debugfs_crc.h | 73 +++++++ 8 files changed, 555 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/drm_debugfs_crc.c create mode 100644 include/drm/drm_debugfs_crc.h diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 1ba301cebe16..de3ac9f90f8f 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -216,3 +216,9 @@ interfaces. Especially since all hardware-acceleration interfaces to userspace are driver specific for efficiency and other reasons these interfaces can be rather substantial. Hence every driver has its own chapter. + +Testing and validation +====================== + +.. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c + :doc: CRC ABI diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 25c720454017..74579d2e796e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -9,7 +9,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_scatter.o drm_pci.o \ drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ - drm_info.o drm_debugfs.o drm_encoder_slave.o \ + drm_info.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ @@ -23,6 +23,7 @@ drm-$(CONFIG_PCI) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o drm-$(CONFIG_AGP) += drm_agpsupport.o +drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2d7bedf28647..60403bf7a4ff 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -122,6 +122,10 @@ static int drm_crtc_register_all(struct drm_device *dev) int ret = 0; drm_for_each_crtc(crtc, dev) { + if (drm_debugfs_crtc_add(crtc)) + DRM_ERROR("Failed to initialize debugfs entry for CRTC '%s'.\n", + crtc->name); + if (crtc->funcs->late_register) ret = crtc->funcs->late_register(crtc); if (ret) @@ -138,9 +142,29 @@ static void drm_crtc_unregister_all(struct drm_device *dev) drm_for_each_crtc(crtc, dev) { if (crtc->funcs->early_unregister) crtc->funcs->early_unregister(crtc); + drm_debugfs_crtc_remove(crtc); } } +static int drm_crtc_crc_init(struct drm_crtc *crtc) +{ +#ifdef CONFIG_DEBUG_FS + spin_lock_init(&crtc->crc.lock); + init_waitqueue_head(&crtc->crc.wq); + crtc->crc.source = kstrdup("auto", GFP_KERNEL); + if (!crtc->crc.source) + return -ENOMEM; +#endif + return 0; +} + +static void drm_crtc_crc_fini(struct drm_crtc *crtc) +{ +#ifdef CONFIG_DEBUG_FS + kfree(crtc->crc.source); +#endif +} + /** * drm_crtc_init_with_planes - Initialise a new CRTC object with * specified primary and cursor planes. @@ -210,6 +234,12 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, if (cursor) cursor->possible_crtcs = 1 << drm_crtc_index(crtc); + ret = drm_crtc_crc_init(crtc); + if (ret) { + drm_mode_object_unregister(dev, &crtc->base); + return ret; + } + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&crtc->base, config->prop_active, 0); drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); @@ -236,6 +266,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) * the indices on the drm_crtc after us in the crtc_list. */ + drm_crtc_crc_fini(crtc); + kfree(crtc->gamma_store); crtc->gamma_store = NULL; diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index fa10cef2ba37..8ea72d821525 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -415,5 +415,37 @@ void drm_debugfs_connector_remove(struct drm_connector *connector) connector->debugfs_entry = NULL; } -#endif /* CONFIG_DEBUG_FS */ +int drm_debugfs_crtc_add(struct drm_crtc *crtc) +{ + struct drm_minor *minor = crtc->dev->primary; + struct dentry *root; + char *name; + name = kasprintf(GFP_KERNEL, "crtc-%d", crtc->index); + if (!name) + return -ENOMEM; + + root = debugfs_create_dir(name, minor->debugfs_root); + kfree(name); + if (!root) + return -ENOMEM; + + crtc->debugfs_entry = root; + + if (drm_debugfs_crtc_crc_add(crtc)) + goto error; + + return 0; + +error: + drm_debugfs_crtc_remove(crtc); + return -ENOMEM; +} + +void drm_debugfs_crtc_remove(struct drm_crtc *crtc) +{ + debugfs_remove_recursive(crtc->debugfs_entry); + crtc->debugfs_entry = NULL; +} + +#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c new file mode 100644 index 000000000000..4129405d17c0 --- /dev/null +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -0,0 +1,351 @@ +/* + * Copyright © 2008 Intel Corporation + * Copyright © 2016 Collabora Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based on code from the i915 driver. + * Original author: Damien Lespiau + * + */ + +#include +#include +#include +#include + +/** + * DOC: CRC ABI + * + * DRM device drivers can provide to userspace CRC information of each frame as + * it reached a given hardware component (a "source"). + * + * Userspace can control generation of CRCs in a given CRTC by writing to the + * file dri/0/crtc-N/crc/control in debugfs, with N being the index of the CRTC. + * Accepted values are source names (which are driver-specific) and the "auto" + * keyword, which will let the driver select a default source of frame CRCs + * for this CRTC. + * + * Once frame CRC generation is enabled, userspace can capture them by reading + * the dri/0/crtc-N/crc/data file. Each line in that file contains the frame + * number in the first field and then a number of unsigned integer fields + * containing the CRC data. Fields are separated by a single space and the number + * of CRC fields is source-specific. + * + * Note that though in some cases the CRC is computed in a specified way and on + * the frame contents as supplied by userspace (eDP 1.3), in general the CRC + * computation is performed in an unspecified way and on frame contents that have + * been already processed in also an unspecified way and thus userspace cannot + * rely on being able to generate matching CRC values for the frame contents that + * it submits. In this general case, the maximum userspace can do is to compare + * the reported CRCs of frames that should have the same contents. + */ + +static int crc_control_show(struct seq_file *m, void *data) +{ + struct drm_crtc *crtc = m->private; + + seq_printf(m, "%s\n", crtc->crc.source); + + return 0; +} + +static int crc_control_open(struct inode *inode, struct file *file) +{ + struct drm_crtc *crtc = inode->i_private; + + return single_open(file, crc_control_show, crtc); +} + +static ssize_t crc_control_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct drm_crtc *crtc = m->private; + struct drm_crtc_crc *crc = &crtc->crc; + char *source; + + if (len == 0) + return 0; + + if (len > PAGE_SIZE - 1) { + DRM_DEBUG_KMS("Expected < %lu bytes into crtc crc control\n", + PAGE_SIZE); + return -E2BIG; + } + + source = memdup_user_nul(ubuf, len); + if (IS_ERR(source)) + return PTR_ERR(source); + + if (source[len] == '\n') + source[len] = '\0'; + + spin_lock_irq(&crc->lock); + + if (crc->opened) { + spin_unlock_irq(&crc->lock); + kfree(source); + return -EBUSY; + } + + kfree(crc->source); + crc->source = source; + + spin_unlock_irq(&crc->lock); + + *offp += len; + return len; +} + +const struct file_operations drm_crtc_crc_control_fops = { + .owner = THIS_MODULE, + .open = crc_control_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = crc_control_write +}; + +static int crtc_crc_open(struct inode *inode, struct file *filep) +{ + struct drm_crtc *crtc = inode->i_private; + struct drm_crtc_crc *crc = &crtc->crc; + struct drm_crtc_crc_entry *entries = NULL; + size_t values_cnt; + int ret; + + if (crc->opened) + return -EBUSY; + + ret = crtc->funcs->set_crc_source(crtc, crc->source, &values_cnt); + if (ret) + return ret; + + if (WARN_ON(values_cnt > DRM_MAX_CRC_NR)) { + ret = -EINVAL; + goto err_disable; + } + + if (WARN_ON(values_cnt == 0)) { + ret = -EINVAL; + goto err_disable; + } + + entries = kcalloc(DRM_CRC_ENTRIES_NR, sizeof(*entries), GFP_KERNEL); + if (!entries) { + ret = -ENOMEM; + goto err_disable; + } + + spin_lock_irq(&crc->lock); + crc->entries = entries; + crc->values_cnt = values_cnt; + crc->opened = true; + spin_unlock_irq(&crc->lock); + + return 0; + +err_disable: + crtc->funcs->set_crc_source(crtc, NULL, &values_cnt); + return ret; +} + +static int crtc_crc_release(struct inode *inode, struct file *filep) +{ + struct drm_crtc *crtc = filep->f_inode->i_private; + struct drm_crtc_crc *crc = &crtc->crc; + size_t values_cnt; + + spin_lock_irq(&crc->lock); + kfree(crc->entries); + crc->entries = NULL; + crc->head = 0; + crc->tail = 0; + crc->values_cnt = 0; + crc->opened = false; + spin_unlock_irq(&crc->lock); + + crtc->funcs->set_crc_source(crtc, NULL, &values_cnt); + + return 0; +} + +static int crtc_crc_data_count(struct drm_crtc_crc *crc) +{ + assert_spin_locked(&crc->lock); + return CIRC_CNT(crc->head, crc->tail, DRM_CRC_ENTRIES_NR); +} + +/* + * 1 frame field of 10 chars plus a number of CRC fields of 10 chars each, space + * separated, with a newline at the end and null-terminated. + */ +#define LINE_LEN(values_cnt) (10 + 11 * values_cnt + 1 + 1) +#define MAX_LINE_LEN (LINE_LEN(DRM_MAX_CRC_NR)) + +static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf, + size_t count, loff_t *pos) +{ + struct drm_crtc *crtc = filep->f_inode->i_private; + struct drm_crtc_crc *crc = &crtc->crc; + struct drm_crtc_crc_entry *entry; + char buf[MAX_LINE_LEN]; + int ret, i; + + spin_lock_irq(&crc->lock); + + if (!crc->source) { + spin_unlock_irq(&crc->lock); + return 0; + } + + /* Nothing to read? */ + while (crtc_crc_data_count(crc) == 0) { + if (filep->f_flags & O_NONBLOCK) { + spin_unlock_irq(&crc->lock); + return -EAGAIN; + } + + ret = wait_event_interruptible_lock_irq(crc->wq, + crtc_crc_data_count(crc), + crc->lock); + if (ret) { + spin_unlock_irq(&crc->lock); + return ret; + } + } + + /* We know we have an entry to be read */ + entry = &crc->entries[crc->tail]; + + if (count < LINE_LEN(crc->values_cnt)) { + spin_unlock_irq(&crc->lock); + return -EINVAL; + } + + BUILD_BUG_ON_NOT_POWER_OF_2(DRM_CRC_ENTRIES_NR); + crc->tail = (crc->tail + 1) & (DRM_CRC_ENTRIES_NR - 1); + + spin_unlock_irq(&crc->lock); + + if (entry->has_frame_counter) + sprintf(buf, "0x%08x", entry->frame); + else + sprintf(buf, "XXXXXXXXXX"); + + for (i = 0; i < crc->values_cnt; i++) + sprintf(buf + 10 + i * 11, " 0x%08x", entry->crcs[i]); + sprintf(buf + 10 + crc->values_cnt * 11, "\n"); + + if (copy_to_user(user_buf, buf, LINE_LEN(crc->values_cnt))) + return -EFAULT; + + return LINE_LEN(crc->values_cnt); +} + +const struct file_operations drm_crtc_crc_data_fops = { + .owner = THIS_MODULE, + .open = crtc_crc_open, + .read = crtc_crc_read, + .release = crtc_crc_release, +}; + +/** + * drm_debugfs_crtc_crc_add - Add files to debugfs for capture of frame CRCs + * @crtc: CRTC to whom the frames will belong + * + * Adds files to debugfs directory that allows userspace to control the + * generation of frame CRCs and to read them. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) +{ + struct dentry *crc_ent, *ent; + + if (!crtc->funcs->set_crc_source) + return 0; + + crc_ent = debugfs_create_dir("crc", crtc->debugfs_entry); + if (!crc_ent) + return -ENOMEM; + + ent = debugfs_create_file("control", S_IRUGO, crc_ent, crtc, + &drm_crtc_crc_control_fops); + if (!ent) + goto error; + + ent = debugfs_create_file("data", S_IRUGO, crc_ent, crtc, + &drm_crtc_crc_data_fops); + if (!ent) + goto error; + + return 0; + +error: + debugfs_remove_recursive(crc_ent); + + return -ENOMEM; +} + +/** + * drm_crtc_add_crc_entry - Add entry with CRC information for a frame + * @crtc: CRTC to which the frame belongs + * @has_frame: whether this entry has a frame number to go with + * @frame: number of the frame these CRCs are about + * @crcs: array of CRC values, with length matching #drm_crtc_crc.values_cnt + * + * For each frame, the driver polls the source of CRCs for new data and calls + * this function to add them to the buffer from where userspace reads. + */ +int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame, + uint32_t frame, uint32_t *crcs) +{ + struct drm_crtc_crc *crc = &crtc->crc; + struct drm_crtc_crc_entry *entry; + int head, tail; + + assert_spin_locked(&crc->lock); + + /* Caller may not have noticed yet that userspace has stopped reading */ + if (!crc->opened) + return -EINVAL; + + head = crc->head; + tail = crc->tail; + + if (CIRC_SPACE(head, tail, DRM_CRC_ENTRIES_NR) < 1) { + DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n"); + return -ENOBUFS; + } + + entry = &crc->entries[head]; + entry->frame = frame; + entry->has_frame_counter = has_frame; + memcpy(&entry->crcs, crcs, sizeof(*crcs) * crc->values_cnt); + + head = (head + 1) & (DRM_CRC_ENTRIES_NR - 1); + crc->head = head; + + return 0; +} +EXPORT_SYMBOL_GPL(drm_crtc_add_crc_entry); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index e66af289a016..abd209863ef4 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -100,6 +100,9 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, int drm_debugfs_cleanup(struct drm_minor *minor); int drm_debugfs_connector_add(struct drm_connector *connector); void drm_debugfs_connector_remove(struct drm_connector *connector); +int drm_debugfs_crtc_add(struct drm_crtc *crtc); +void drm_debugfs_crtc_remove(struct drm_crtc *crtc); +int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc); #else static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root) @@ -119,4 +122,17 @@ static inline int drm_debugfs_connector_add(struct drm_connector *connector) static inline void drm_debugfs_connector_remove(struct drm_connector *connector) { } + +static inline int drm_debugfs_crtc_add(struct drm_crtc *crtc) +{ + return 0; +} +static inline void drm_debugfs_crtc_remove(struct drm_crtc *crtc) +{ +} + +static inline int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) +{ + return 0; +} #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 4633915cb51b..284c1b3aec10 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -47,6 +47,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -569,6 +570,30 @@ struct drm_crtc_funcs { * before data structures are torndown. */ void (*early_unregister)(struct drm_crtc *crtc); + + /** + * @set_crc_source: + * + * Changes the source of CRC checksums of frames at the request of + * userspace, typically for testing purposes. The sources available are + * specific of each driver and a %NULL value indicates that CRC + * generation is to be switched off. + * + * When CRC generation is enabled, the driver should call + * drm_crtc_add_crc_entry() at each frame, providing any information + * that characterizes the frame contents in the crcN arguments, as + * provided from the configured source. Drivers must accept a "auto" + * source name that will select a default source for this CRTC. + * + * This callback is optional if the driver does not support any CRC + * generation functionality. + * + * RETURNS: + * + * 0 on success or a negative error code on failure. + */ + int (*set_crc_source)(struct drm_crtc *crtc, const char *source, + size_t *values_cnt); }; /** @@ -685,6 +710,22 @@ struct drm_crtc { * context. */ struct drm_modeset_acquire_ctx *acquire_ctx; + +#ifdef CONFIG_DEBUG_FS + /** + * @debugfs_entry: + * + * Debugfs directory for this CRTC. + */ + struct dentry *debugfs_entry; + + /** + * @crc: + * + * Configuration settings of CRC capture. + */ + struct drm_crtc_crc crc; +#endif }; /** diff --git a/include/drm/drm_debugfs_crc.h b/include/drm/drm_debugfs_crc.h new file mode 100644 index 000000000000..7d63b1d4adb9 --- /dev/null +++ b/include/drm/drm_debugfs_crc.h @@ -0,0 +1,73 @@ +/* + * Copyright © 2016 Collabora Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __DRM_DEBUGFS_CRC_H__ +#define __DRM_DEBUGFS_CRC_H__ + +#define DRM_MAX_CRC_NR 10 + +/** + * struct drm_crtc_crc_entry - entry describing a frame's content + * @has_frame_counter: whether the source was able to provide a frame number + * @frame: number of the frame this CRC is about, if @has_frame_counter is true + * @crc: array of values that characterize the frame + */ +struct drm_crtc_crc_entry { + bool has_frame_counter; + uint32_t frame; + uint32_t crcs[DRM_MAX_CRC_NR]; +}; + +#define DRM_CRC_ENTRIES_NR 128 + +/** + * struct drm_crtc_crc - data supporting CRC capture on a given CRTC + * @lock: protects the fields in this struct + * @source: name of the currently configured source of CRCs + * @opened: whether userspace has opened the data file for reading + * @entries: array of entries, with size of %DRM_CRC_ENTRIES_NR + * @head: head of circular queue + * @tail: tail of circular queue + * @values_cnt: number of CRC values per entry, up to %DRM_MAX_CRC_NR + * @wq: workqueue used to synchronize reading and writing + */ +struct drm_crtc_crc { + spinlock_t lock; + const char *source; + bool opened; + struct drm_crtc_crc_entry *entries; + int head, tail; + size_t values_cnt; + wait_queue_head_t wq; +}; + +#if defined(CONFIG_DEBUG_FS) +int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame, + uint32_t frame, uint32_t *crcs); +#else +static inline int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame, + uint32_t frame, uint32_t *crcs) +{ + return -EINVAL; +} +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* __DRM_DEBUGFS_CRC_H__ */ From cff52e5fc4cfc978b7df898dc14a0492c7ef0ae8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:13:39 +0200 Subject: [PATCH 25/55] drm: avoid uninitialized timestamp use in wait_vblank gcc warns about the timestamp in drm_wait_vblank being possibly used without an initialization: drivers/gpu/drm/drm_irq.c: In function 'drm_crtc_send_vblank_event': drivers/gpu/drm/drm_irq.c:992:24: error: 'now.tv_usec' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/gpu/drm/drm_irq.c:1069:17: note: 'now.tv_usec' was declared here drivers/gpu/drm/drm_irq.c:991:23: error: 'now.tv_sec' may be used uninitialized in this function [-Werror=maybe-uninitialized] This can happen if drm_vblank_count_and_time() returns 0 in its error path. To sanitize the error case, I'm changing that function to return a zero timestamp when it fails. Fixes: e6ae8687a87b ("drm: idiot-proof vblank") Reviewed-by: David Herrmann Cc: Rob Clark Cc: Daniel Vetter Signed-off-by: Arnd Bergmann Reviewed-by: Mario Kleiner Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161017221355.1861551-6-arnd@arndb.de --- drivers/gpu/drm/drm_irq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index b969a64a1514..48a6167f5e7b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -952,8 +952,10 @@ static u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, u32 vblank_count; unsigned int seq; - if (WARN_ON(pipe >= dev->num_crtcs)) + if (WARN_ON(pipe >= dev->num_crtcs)) { + *vblanktime = (struct timeval) { 0 }; return 0; + } do { seq = read_seqbegin(&vblank->seqlock); From 84770cc24f3a51c05055665feeac1dcf22119d69 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:09 +0300 Subject: [PATCH 26/55] drm: Centralize format information Various pieces of information about DRM formats (number of planes, color depth, chroma subsampling, ...) are scattered across different helper functions in the DRM core. Callers of those functions often need to access more than a single parameter of the format, leading to inefficiencies due to multiple lookups. Centralize all format information in a data structure and create a function to look up information based on the format 4CC. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Reviewed-by: Eric Engestrom Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-2-git-send-email-laurent.pinchart@ideasonboard.com --- Documentation/gpu/drm-kms.rst | 3 ++ drivers/gpu/drm/drm_fourcc.c | 84 +++++++++++++++++++++++++++++++++++ include/drm/drm_fourcc.h | 21 +++++++++ 3 files changed, 108 insertions(+) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 53b872c105d2..cb0d3537b705 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -63,6 +63,9 @@ Frame Buffer Functions Reference DRM Format Handling =================== +.. kernel-doc:: include/drm/drm_fourcc.h + :internal: + .. kernel-doc:: drivers/gpu/drm/drm_fourcc.c :export: diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 29c56b4331e0..39f09c564111 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -102,6 +102,90 @@ char *drm_get_format_name(uint32_t format) } EXPORT_SYMBOL(drm_get_format_name); +/** + * drm_format_info - query information for a given format + * @format: pixel format (DRM_FORMAT_*) + * + * Returns: + * The instance of struct drm_format_info that describes the pixel format, or + * NULL if the format is unsupported. + */ +const struct drm_format_info *drm_format_info(u32 format) +{ + static const struct drm_format_info formats[] = { + { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XBGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRX4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ARGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ABGR4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRA4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XRGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XBGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRX5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ARGB1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ABGR1555, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRA5551, .depth = 15, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGB565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGR565, .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGB888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGR888, .depth = 24, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ARGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ABGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRA1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, + { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, + { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, + { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, + { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, + { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, + { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, + { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, + { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, + { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 }, + }; + + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (formats[i].format == format) + return &formats[i]; + } + + return NULL; +} +EXPORT_SYMBOL(drm_format_info); + /** * drm_fb_get_bpp_depth - get the bpp/depth values for format * @format: pixel format (DRM_FORMAT_*) diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 30c30fa87ee8..135fef050ee6 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -25,6 +25,27 @@ #include #include +/** + * struct drm_format_info - information about a DRM format + * @format: 4CC format identifier (DRM_FORMAT_*) + * @depth: Color depth (number of bits per pixel excluding padding bits), + * valid for a subset of RGB formats only. This is a legacy field, do not + * use in new code and set to 0 for new formats. + * @num_planes: Number of color planes (1 to 3) + * @cpp: Number of bytes per pixel (per plane) + * @hsub: Horizontal chroma subsampling factor + * @vsub: Vertical chroma subsampling factor + */ +struct drm_format_info { + u32 format; + u8 depth; + u8 num_planes; + u8 cpp[3]; + u8 hsub; + u8 vsub; +}; + +const struct drm_format_info *drm_format_info(u32 format); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); int drm_format_num_planes(uint32_t format); From 86c238aa51c219b8ba1a0e6a86c2676d856f90d5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:10 +0300 Subject: [PATCH 27/55] drm: Implement the drm_format_*() helpers as drm_format_info() wrappers Turn the drm_format_*() helpers into wrappers around the drm_format_info lookup function to centralize all format information in a single place. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Reviewed-by: Daniel Vetter Reviewed-by: Eric Engestrom Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-3-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/drm_fourcc.c | 184 +++++++---------------------------- 1 file changed, 36 insertions(+), 148 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 39f09c564111..23d4b82ec17c 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -198,69 +198,22 @@ EXPORT_SYMBOL(drm_format_info); void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { - char *format_name; + const struct drm_format_info *info; + + info = drm_format_info(format); + if (!info || !info->depth) { + char *format_name = drm_get_format_name(format); - switch (format) { - case DRM_FORMAT_C8: - case DRM_FORMAT_RGB332: - case DRM_FORMAT_BGR233: - *depth = 8; - *bpp = 8; - break; - case DRM_FORMAT_XRGB1555: - case DRM_FORMAT_XBGR1555: - case DRM_FORMAT_RGBX5551: - case DRM_FORMAT_BGRX5551: - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_ABGR1555: - case DRM_FORMAT_RGBA5551: - case DRM_FORMAT_BGRA5551: - *depth = 15; - *bpp = 16; - break; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_BGR565: - *depth = 16; - *bpp = 16; - break; - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - *depth = 24; - *bpp = 24; - break; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBX8888: - case DRM_FORMAT_BGRX8888: - *depth = 24; - *bpp = 32; - break; - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_RGBA1010102: - case DRM_FORMAT_BGRA1010102: - *depth = 30; - *bpp = 32; - break; - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - *depth = 32; - *bpp = 32; - break; - default: - format_name = drm_get_format_name(format); DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name); kfree(format_name); + *depth = 0; *bpp = 0; - break; + return; } + + *depth = info->depth; + *bpp = info->cpp[0] * 8; } EXPORT_SYMBOL(drm_fb_get_bpp_depth); @@ -273,28 +226,10 @@ EXPORT_SYMBOL(drm_fb_get_bpp_depth); */ int drm_format_num_planes(uint32_t format) { - switch (format) { - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 3; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - return 2; - default: - return 1; - } + const struct drm_format_info *info; + + info = drm_format_info(format); + return info ? info->num_planes : 1; } EXPORT_SYMBOL(drm_format_num_planes); @@ -308,40 +243,13 @@ EXPORT_SYMBOL(drm_format_num_planes); */ int drm_format_plane_cpp(uint32_t format, int plane) { - unsigned int depth; - int bpp; + const struct drm_format_info *info; - if (plane >= drm_format_num_planes(format)) + info = drm_format_info(format); + if (!info || plane >= info->num_planes) return 0; - switch (format) { - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - return 2; - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - return plane ? 2 : 1; - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 1; - default: - drm_fb_get_bpp_depth(format, &depth, &bpp); - return bpp >> 3; - } + return info->cpp[plane]; } EXPORT_SYMBOL(drm_format_plane_cpp); @@ -355,28 +263,10 @@ EXPORT_SYMBOL(drm_format_plane_cpp); */ int drm_format_horz_chroma_subsampling(uint32_t format) { - switch (format) { - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - return 4; - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - return 2; - default: - return 1; - } + const struct drm_format_info *info; + + info = drm_format_info(format); + return info ? info->hsub : 1; } EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); @@ -390,18 +280,10 @@ EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); */ int drm_format_vert_chroma_subsampling(uint32_t format) { - switch (format) { - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - return 4; - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - return 2; - default: - return 1; - } + const struct drm_format_info *info; + + info = drm_format_info(format); + return info ? info->vsub : 1; } EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); @@ -416,13 +298,16 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); */ int drm_format_plane_width(int width, uint32_t format, int plane) { - if (plane >= drm_format_num_planes(format)) + const struct drm_format_info *info; + + info = drm_format_info(format); + if (!info || plane >= info->num_planes) return 0; if (plane == 0) return width; - return width / drm_format_horz_chroma_subsampling(format); + return width / info->hsub; } EXPORT_SYMBOL(drm_format_plane_width); @@ -437,12 +322,15 @@ EXPORT_SYMBOL(drm_format_plane_width); */ int drm_format_plane_height(int height, uint32_t format, int plane) { - if (plane >= drm_format_num_planes(format)) + const struct drm_format_info *info; + + info = drm_format_info(format); + if (!info || plane >= info->num_planes) return 0; if (plane == 0) return height; - return height / drm_format_vert_chroma_subsampling(format); + return height / info->vsub; } EXPORT_SYMBOL(drm_format_plane_height); From d549349007ed66af325c1363c0e4f8bb7a518c0d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:11 +0300 Subject: [PATCH 28/55] drm: Use drm_format_info() in DRM core code Replace calls to the drm_format_*() helper functions with direct use of the drm_format_info structure. This improves efficiency by removing duplicate lookups. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Reviewed-by: Eric Engestrom Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-4-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/drm_fb_cma_helper.c | 23 ++++--- drivers/gpu/drm/drm_framebuffer.c | 102 ++++------------------------ 2 files changed, 25 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 1fd6eac1400c..fac4f06f8485 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -176,20 +176,20 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd, const struct drm_framebuffer_funcs *funcs) { + const struct drm_format_info *info; struct drm_fb_cma *fb_cma; struct drm_gem_cma_object *objs[4]; struct drm_gem_object *obj; - unsigned int hsub; - unsigned int vsub; int ret; int i; - hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); - vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); + info = drm_format_info(mode_cmd->pixel_format); + if (!info) + return ERR_PTR(-EINVAL); - for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) { - unsigned int width = mode_cmd->width / (i ? hsub : 1); - unsigned int height = mode_cmd->height / (i ? vsub : 1); + for (i = 0; i < info->num_planes; i++) { + unsigned int width = mode_cmd->width / (i ? info->hsub : 1); + unsigned int height = mode_cmd->height / (i ? info->vsub : 1); unsigned int min_size; obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]); @@ -200,7 +200,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, } min_size = (height - 1) * mode_cmd->pitches[i] - + width * drm_format_plane_cpp(mode_cmd->pixel_format, i) + + width * info->cpp[i] + mode_cmd->offsets[i]; if (obj->size < min_size) { @@ -269,12 +269,15 @@ EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m) { struct drm_fb_cma *fb_cma = to_fb_cma(fb); - int i, n = drm_format_num_planes(fb->pixel_format); + const struct drm_format_info *info; + int i; seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height, (char *)&fb->pixel_format); - for (i = 0; i < n; i++) { + info = drm_format_info(fb->pixel_format); + + for (i = 0; i < info->num_planes; i++) { seq_printf(m, " %d: offset=%d pitch=%d, obj: ", i, fb->offsets[i], fb->pitches[i]); drm_gem_cma_describe(fb_cma->obj[i], m); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 398efd67cb93..386977df72ce 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -126,111 +126,33 @@ int drm_mode_addfb(struct drm_device *dev, return 0; } -static int format_check(const struct drm_mode_fb_cmd2 *r) -{ - uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; - char *format_name; - - switch (format) { - case DRM_FORMAT_C8: - case DRM_FORMAT_RGB332: - case DRM_FORMAT_BGR233: - case DRM_FORMAT_XRGB4444: - case DRM_FORMAT_XBGR4444: - case DRM_FORMAT_RGBX4444: - case DRM_FORMAT_BGRX4444: - case DRM_FORMAT_ARGB4444: - case DRM_FORMAT_ABGR4444: - case DRM_FORMAT_RGBA4444: - case DRM_FORMAT_BGRA4444: - case DRM_FORMAT_XRGB1555: - case DRM_FORMAT_XBGR1555: - case DRM_FORMAT_RGBX5551: - case DRM_FORMAT_BGRX5551: - case DRM_FORMAT_ARGB1555: - case DRM_FORMAT_ABGR1555: - case DRM_FORMAT_RGBA5551: - case DRM_FORMAT_BGRA5551: - case DRM_FORMAT_RGB565: - case DRM_FORMAT_BGR565: - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBX8888: - case DRM_FORMAT_BGRX8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_RGBA1010102: - case DRM_FORMAT_BGRA1010102: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_AYUV: - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV21: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV61: - case DRM_FORMAT_NV24: - case DRM_FORMAT_NV42: - case DRM_FORMAT_YUV410: - case DRM_FORMAT_YVU410: - case DRM_FORMAT_YUV411: - case DRM_FORMAT_YVU411: - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - case DRM_FORMAT_YUV422: - case DRM_FORMAT_YVU422: - case DRM_FORMAT_YUV444: - case DRM_FORMAT_YVU444: - return 0; - default: - format_name = drm_get_format_name(r->pixel_format); - DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); - kfree(format_name); - return -EINVAL; - } -} - static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) { - int ret, hsub, vsub, num_planes, i; + const struct drm_format_info *info; + int i; - ret = format_check(r); - if (ret) { + info = drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); + if (!info) { char *format_name = drm_get_format_name(r->pixel_format); DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); kfree(format_name); - return ret; + return -EINVAL; } - hsub = drm_format_horz_chroma_subsampling(r->pixel_format); - vsub = drm_format_vert_chroma_subsampling(r->pixel_format); - num_planes = drm_format_num_planes(r->pixel_format); - - if (r->width == 0 || r->width % hsub) { + if (r->width == 0 || r->width % info->hsub) { DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); return -EINVAL; } - if (r->height == 0 || r->height % vsub) { + if (r->height == 0 || r->height % info->vsub) { DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); return -EINVAL; } - for (i = 0; i < num_planes; i++) { - unsigned int width = r->width / (i != 0 ? hsub : 1); - unsigned int height = r->height / (i != 0 ? vsub : 1); - unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); + for (i = 0; i < info->num_planes; i++) { + unsigned int width = r->width / (i != 0 ? info->hsub : 1); + unsigned int height = r->height / (i != 0 ? info->vsub : 1); + unsigned int cpp = info->cpp[i]; if (!r->handles[i]) { DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); @@ -273,7 +195,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) } } - for (i = num_planes; i < 4; i++) { + for (i = info->num_planes; i < 4; i++) { if (r->modifier[i]) { DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); return -EINVAL; From 333d2da5b7cf8046aee88c0412170be5f6f1ed55 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:12 +0300 Subject: [PATCH 29/55] drm: WARN when calling drm_format_info() for an unsupported format The format helpers have historically treated unsupported formats as part of the default case, returning values that are likely wrong. We can't change this behaviour now without risking breaking drivers in difficult to detect ways, but we can WARN on unsupported formats to catch faulty callers. The only exception is the framebuffer_check() function that calls drm_format_info() to validate the format passed from userspace. This is a valid use case that shouldn't generate a warning. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-5-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/drm_fourcc.c | 32 +++++++++++++++++++++++-------- drivers/gpu/drm/drm_framebuffer.c | 2 +- include/drm/drm_fourcc.h | 1 + 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 23d4b82ec17c..523ed916a1c0 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -102,15 +102,11 @@ char *drm_get_format_name(uint32_t format) } EXPORT_SYMBOL(drm_get_format_name); -/** - * drm_format_info - query information for a given format - * @format: pixel format (DRM_FORMAT_*) - * - * Returns: - * The instance of struct drm_format_info that describes the pixel format, or - * NULL if the format is unsupported. +/* + * Internal function to query information for a given format. See + * drm_format_info() for the public API. */ -const struct drm_format_info *drm_format_info(u32 format) +const struct drm_format_info *__drm_format_info(u32 format) { static const struct drm_format_info formats[] = { { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, @@ -184,6 +180,26 @@ const struct drm_format_info *drm_format_info(u32 format) return NULL; } + +/** + * drm_format_info - query information for a given format + * @format: pixel format (DRM_FORMAT_*) + * + * The caller should only pass a supported pixel format to this function. + * Unsupported pixel formats will generate a warning in the kernel log. + * + * Returns: + * The instance of struct drm_format_info that describes the pixel format, or + * NULL if the format is unsupported. + */ +const struct drm_format_info *drm_format_info(u32 format) +{ + const struct drm_format_info *info; + + info = __drm_format_info(format); + WARN_ON(!info); + return info; +} EXPORT_SYMBOL(drm_format_info); /** diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 386977df72ce..49fd7db758e0 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -131,7 +131,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) const struct drm_format_info *info; int i; - info = drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); + info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); if (!info) { char *format_name = drm_get_format_name(r->pixel_format); DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 135fef050ee6..f73f97afd1e2 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -45,6 +45,7 @@ struct drm_format_info { u8 vsub; }; +const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); From ba0891d1120389ad44c4f4e6d0b71f5fbcc23163 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:13 +0300 Subject: [PATCH 30/55] drm: hdlcd: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver needs the number of bytes per pixel, not the bpp and depth info meant for fbdev compatibility. Use the right API. Signed-off-by: Laurent Pinchart Acked-by: Liviu Dudau Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-6-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/arm/hdlcd_crtc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index 48019ae22ddb..bbaa55add2d2 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -223,14 +223,12 @@ static void hdlcd_plane_atomic_update(struct drm_plane *plane, { struct hdlcd_drm_private *hdlcd; struct drm_gem_cma_object *gem; - unsigned int depth, bpp; u32 src_w, src_h, dest_w, dest_h; dma_addr_t scanout_start; if (!plane->state->fb) return; - drm_fb_get_bpp_depth(plane->state->fb->pixel_format, &depth, &bpp); src_w = plane->state->src_w >> 16; src_h = plane->state->src_h >> 16; dest_w = plane->state->crtc_w; @@ -238,7 +236,8 @@ static void hdlcd_plane_atomic_update(struct drm_plane *plane, gem = drm_fb_cma_get_gem_obj(plane->state->fb, 0); scanout_start = gem->paddr + plane->state->fb->offsets[0] + plane->state->crtc_y * plane->state->fb->pitches[0] + - plane->state->crtc_x * bpp / 8; + plane->state->crtc_x * + drm_format_plane_cpp(plane->state->fb->pixel_format, 0); hdlcd = plane->dev->dev_private; hdlcd_write(hdlcd, HDLCD_REG_FB_LINE_LENGTH, plane->state->fb->pitches[0]); From 59f11a43237fe08de8572b5be5d961d262ae770d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:14 +0300 Subject: [PATCH 31/55] drm: tilcdc: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver needs the number of bytes per pixel, not the bpp and depth info meant for fbdev compatibility. Use the right API. In the tilcdc_crtc_mode_set() function compute the hardware register value directly from the pixel format instead of computing the number of bits per pixels first. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-7-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 18 ++++++++---------- drivers/gpu/drm/tilcdc/tilcdc_plane.c | 7 ++++--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 52ebe8fc1784..822531ebd4b0 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -72,16 +72,14 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_gem_cma_object *gem; - unsigned int depth, bpp; dma_addr_t start, end; u64 dma_base_and_ceiling; - drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); gem = drm_fb_cma_get_gem_obj(fb, 0); start = gem->paddr + fb->offsets[0] + crtc->y * fb->pitches[0] + - crtc->x * bpp / 8; + crtc->x * drm_format_plane_cpp(fb->pixel_format, 0); end = start + (crtc->mode.vdisplay * fb->pitches[0]); @@ -461,16 +459,16 @@ static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (info->tft_alt_mode) reg |= LCDC_TFT_ALT_ENABLE; if (priv->rev == 2) { - unsigned int depth, bpp; - - drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); - switch (bpp) { - case 16: + switch (fb->pixel_format) { + case DRM_FORMAT_BGR565: + case DRM_FORMAT_RGB565: break; - case 32: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: reg |= LCDC_V2_TFT_24BPP_UNPACK; /* fallthrough */ - case 24: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: reg |= LCDC_V2_TFT_24BPP_MODE; break; default: diff --git a/drivers/gpu/drm/tilcdc/tilcdc_plane.c b/drivers/gpu/drm/tilcdc/tilcdc_plane.c index 74c65fa859b2..8a6a50d74aff 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_plane.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_plane.c @@ -39,7 +39,7 @@ static int tilcdc_plane_atomic_check(struct drm_plane *plane, { struct drm_crtc_state *crtc_state; struct drm_plane_state *old_state = plane->state; - unsigned int depth, bpp; + unsigned int pitch; if (!state->crtc) return 0; @@ -68,8 +68,9 @@ static int tilcdc_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - drm_fb_get_bpp_depth(state->fb->pixel_format, &depth, &bpp); - if (state->fb->pitches[0] != crtc_state->mode.hdisplay * bpp / 8) { + pitch = crtc_state->mode.hdisplay * + drm_format_plane_cpp(state->fb->pixel_format, 0); + if (state->fb->pitches[0] != pitch) { dev_err(plane->dev->dev, "Invalid pitch: fb and crtc widths must be the same"); return -EINVAL; From b7f9745cda2f905403cf0c8ce326e70ee9f8b633 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:15 +0300 Subject: [PATCH 32/55] drm: cirrus: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver doesn't need the color depth, only the number of bits per pixel. Use the right API. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-8-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/cirrus/cirrus_fbdev.c | 6 +++--- drivers/gpu/drm/cirrus/cirrus_main.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index daecf1ad76a4..3a6309d7d8e4 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -138,12 +138,12 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, { struct drm_device *dev = afbdev->helper.dev; struct cirrus_device *cdev = dev->dev_private; - u32 bpp, depth; + u32 bpp; u32 size; struct drm_gem_object *gobj; - int ret = 0; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + + bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, bpp, mode_cmd->pitches[0])) diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 76bcb43e7c06..2c3c0d4072ce 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -52,10 +52,10 @@ cirrus_user_framebuffer_create(struct drm_device *dev, struct cirrus_device *cdev = dev->dev_private; struct drm_gem_object *obj; struct cirrus_framebuffer *cirrus_fb; + u32 bpp; int ret; - u32 bpp, depth; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + bpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0) * 8; if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, bpp, mode_cmd->pitches[0])) From e0f9a4ab49a107c011f3bda401f747fbb5f29e7a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:16 +0300 Subject: [PATCH 33/55] drm: gma500: Replace drm_fb_get_bpp_depth() with drm_format_info() The driver uses drm_fb_get_bpp_depth() to check whether it can support the format requested by userspace when creating a framebuffer. This isn't the right API, as it doesn't differentiate between RGB formats other than on a depth and bpp basis. Fixing this requires non trivial changes to the drivers internals. As a first step, replace usage of the drm_fb_get_bpp_depth() function with an equivalent check based on drm_format_info(). This is part of a wider effort to remove usage of the drm_fb_get_bpp_depth() function in drivers. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-9-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/gma500/framebuffer.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index aee2f9733457..97daf23f3fef 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -236,22 +236,20 @@ static int psb_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct gtt_range *gt) { - u32 bpp, depth; + const struct drm_format_info *info; int ret; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + /* + * Reject unknown formats, YUV formats, and formats with more than + * 4 bytes per pixel. + */ + info = drm_format_info(mode_cmd->pixel_format); + if (!info || !info->depth || info->cpp[0] > 4) + return -EINVAL; if (mode_cmd->pitches[0] & 63) return -EINVAL; - switch (bpp) { - case 8: - case 16: - case 24: - case 32: - break; - default: - return -EINVAL; - } + drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); fb->gtt = gt; ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs); From 8e911ab770f7bbc8bb5fab0ce6ebd8d1a7188998 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:17 +0300 Subject: [PATCH 34/55] drm: amdgpu: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver needs the number of bytes per pixel, not the bpp and depth info meant for fbdev compatibility. Use the right API. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-10-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 14 +++++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 9fb8aa4d6bae..8d01aa24d68a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -90,12 +90,12 @@ static struct fb_ops amdgpufb_ops = { }; -int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tiled) +int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int cpp, bool tiled) { int aligned = width; int pitch_mask = 0; - switch (bpp / 8) { + switch (cpp) { case 1: pitch_mask = 255; break; @@ -110,7 +110,7 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile aligned += pitch_mask; aligned &= ~pitch_mask; - return aligned; + return aligned * cpp; } static void amdgpufb_destroy_pinned_object(struct drm_gem_object *gobj) @@ -139,13 +139,13 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, int ret; int aligned_size, size; int height = mode_cmd->height; - u32 bpp, depth; + u32 cpp; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); /* need to align pitch with crtc limits */ - mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, bpp, - fb_tiled) * ((bpp + 1) / 8); + mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, cpp, + fb_tiled); height = ALIGN(mode_cmd->height, 8); size = mode_cmd->pitches[0] * height; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index e0171c75b60c..3ad0bf6ce3e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -702,7 +702,8 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, uint32_t handle; int r; - args->pitch = amdgpu_align_pitch(adev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8); + args->pitch = amdgpu_align_pitch(adev, args->width, + DIV_ROUND_UP(args->bpp, 8), 0); args->size = (u64)args->pitch * args->height; args->size = ALIGN(args->size, PAGE_SIZE); From 802aaf7642f57aa2eadbff8ee38dbd976e8bd0f4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:18 +0300 Subject: [PATCH 35/55] drm: radeon: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver needs the number of bytes per pixel, not the bpp and depth info meant for fbdev compatibility. Use the right API. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-11-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/radeon/radeon_fb.c | 20 ++++++++++---------- drivers/gpu/drm/radeon/radeon_gem.c | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 0daad446d2c7..f65f29911dca 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -89,13 +89,13 @@ static struct fb_ops radeonfb_ops = { }; -int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) +int radeon_align_pitch(struct radeon_device *rdev, int width, int cpp, bool tiled) { int aligned = width; int align_large = (ASIC_IS_AVIVO(rdev)) || tiled; int pitch_mask = 0; - switch (bpp / 8) { + switch (cpp) { case 1: pitch_mask = align_large ? 255 : 127; break; @@ -110,7 +110,7 @@ int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tile aligned += pitch_mask; aligned &= ~pitch_mask; - return aligned; + return aligned * cpp; } static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) @@ -139,13 +139,13 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, int ret; int aligned_size, size; int height = mode_cmd->height; - u32 bpp, depth; + u32 cpp; - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); + cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); /* need to align pitch with crtc limits */ - mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, bpp, - fb_tiled) * ((bpp + 1) / 8); + mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, cpp, + fb_tiled); if (rdev->family >= CHIP_R600) height = ALIGN(mode_cmd->height, 8); @@ -165,11 +165,11 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, tiling_flags = RADEON_TILING_MACRO; #ifdef __BIG_ENDIAN - switch (bpp) { - case 32: + switch (cpp) { + case 4: tiling_flags |= RADEON_TILING_SWAP_32BIT; break; - case 16: + case 2: tiling_flags |= RADEON_TILING_SWAP_16BIT; default: break; diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index deb9511725c9..0bcffd8a7bd3 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -745,7 +745,8 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, uint32_t handle; int r; - args->pitch = radeon_align_pitch(rdev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8); + args->pitch = radeon_align_pitch(rdev, args->width, + DIV_ROUND_UP(args->bpp, 8), 0); args->size = args->pitch * args->height; args->size = ALIGN(args->size, PAGE_SIZE); From 6c5d064a2dd9ecda0716f66b0586349179036ca4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:19 +0300 Subject: [PATCH 36/55] drm: vmwgfx: Replace drm_fb_get_bpp_depth() with drm_format_info() The driver is the last users of the drm_fb_get_bpp_depth() function. It should ideally be converted to use struct drm_mode_fb_cmd2 instead of the legacy struct drm_mode_fb_cmd internally, but that will require broad changes across the code base. As a first step, replace drm_fb_get_bpp_depth() with drm_format_info() in order to stop exporting the function to drivers. The new DRM_ERROR() message comes from the vmw_create_dmabuf_proxy(), vmw_kms_new_framebuffer_surface() and vmw_kms_new_framebuffer_dmabuf() functions that currently print an error if the pixel format is unsupported. Signed-off-by: Laurent Pinchart Reviewed-by: Sinclair Yeh Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-12-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bf28ccc150df..c965514b82be 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -980,14 +980,22 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; struct drm_mode_fb_cmd mode_cmd; + const struct drm_format_info *info; int ret; + info = drm_format_info(mode_cmd2->pixel_format); + if (!info || !info->depth) { + DRM_ERROR("Unsupported framebuffer format %s\n", + drm_get_format_name(mode_cmd2->pixel_format)); + return ERR_PTR(-EINVAL); + } + mode_cmd.width = mode_cmd2->width; mode_cmd.height = mode_cmd2->height; mode_cmd.pitch = mode_cmd2->pitches[0]; mode_cmd.handle = mode_cmd2->handles[0]; - drm_fb_get_bpp_depth(mode_cmd2->pixel_format, &mode_cmd.depth, - &mode_cmd.bpp); + mode_cmd.depth = info->depth; + mode_cmd.bpp = info->cpp[0] * 8; /** * This code should be conditioned on Screen Objects not being used. From 7ccf281fb1f9e72a18fd0eafefb321f83247e26a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:20 +0300 Subject: [PATCH 37/55] drm/arm: mali-dp: Replace drm_fb_get_bpp_depth() with drm_format_plane_cpp() The driver doesn't need the color depth, only the number of bits per pixel. Use the right API. Signed-off-by: Laurent Pinchart Reviewed-by: Daniel Vetter Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-13-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/arm/malidp_hw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index a6132f1d58c1..be815d0cc772 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -198,9 +198,6 @@ static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode * static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt) { - unsigned int depth; - int bpp; - /* RGB888 or BGR888 can't be rotated */ if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888)) return -EINVAL; @@ -210,9 +207,7 @@ static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 * worth of pixel data. Required size is then: * size = rotated_width * (bpp / 8) * 8; */ - drm_fb_get_bpp_depth(fmt, &depth, &bpp); - - return w * bpp; + return w * drm_format_plane_cpp(fmt, 0) * 8; } static int malidp550_query_hw(struct malidp_hw_device *hwdev) From 488546fc4d246698d4db9c46f7ec06c4839a18e1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 18 Oct 2016 01:41:21 +0300 Subject: [PATCH 38/55] drm: Don't export the drm_fb_get_bpp_depth() function The function is only used by the drm_helper_mode_fill_fb_struct() core function to fill the drm_framebuffer bpp and depth fields, used by drivers that haven't been converted to use pixel formats directly yet. It should not be used by new drivers, so inline it in its only caller. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1476744081-24485-14-git-send-email-laurent.pinchart@ideasonboard.com --- drivers/gpu/drm/drm_fourcc.c | 31 ---------------------------- drivers/gpu/drm/drm_modeset_helper.c | 17 +++++++++++++-- include/drm/drm_fourcc.h | 1 - 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 523ed916a1c0..cbb8b77c363c 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -202,37 +202,6 @@ const struct drm_format_info *drm_format_info(u32 format) } EXPORT_SYMBOL(drm_format_info); -/** - * drm_fb_get_bpp_depth - get the bpp/depth values for format - * @format: pixel format (DRM_FORMAT_*) - * @depth: storage for the depth value - * @bpp: storage for the bpp value - * - * This only supports RGB formats here for compat with code that doesn't use - * pixel formats directly yet. - */ -void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, - int *bpp) -{ - const struct drm_format_info *info; - - info = drm_format_info(format); - if (!info || !info->depth) { - char *format_name = drm_get_format_name(format); - - DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name); - kfree(format_name); - - *depth = 0; - *bpp = 0; - return; - } - - *depth = info->depth; - *bpp = info->cpp[0] * 8; -} -EXPORT_SYMBOL(drm_fb_get_bpp_depth); - /** * drm_format_num_planes - get the number of planes for format * @format: pixel format (DRM_FORMAT_*) diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 1d45738f8f98..2544dfe7354c 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -70,8 +70,23 @@ EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, const struct drm_mode_fb_cmd2 *mode_cmd) { + const struct drm_format_info *info; int i; + info = drm_format_info(mode_cmd->pixel_format); + if (!info || !info->depth) { + char *format_name = drm_get_format_name(mode_cmd->pixel_format); + + DRM_DEBUG_KMS("non-RGB pixel format %s\n", format_name); + kfree(format_name); + + fb->depth = 0; + fb->bits_per_pixel = 0; + } else { + fb->depth = info->depth; + fb->bits_per_pixel = info->cpp[0] * 8; + } + fb->width = mode_cmd->width; fb->height = mode_cmd->height; for (i = 0; i < 4; i++) { @@ -79,8 +94,6 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, fb->offsets[i] = mode_cmd->offsets[i]; fb->modifier[i] = mode_cmd->modifier[i]; } - drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth, - &fb->bits_per_pixel); fb->pixel_format = mode_cmd->pixel_format; fb->flags = mode_cmd->flags; } diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index f73f97afd1e2..dc0aafab9ffd 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -48,7 +48,6 @@ struct drm_format_info { const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); -void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp); int drm_format_num_planes(uint32_t format); int drm_format_plane_cpp(uint32_t format, int plane); int drm_format_horz_chroma_subsampling(uint32_t format); From b9a1b7179cde240abf67a613f2a67be7c56cc59f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 17:16:23 +0200 Subject: [PATCH 39/55] i915: don't call drm_atomic_state_put on invalid pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The introduction of reference counting on the state structures caused sanitize_watermarks() in i915 to break in the error handling case, as pointed out by gcc -Wmaybe-uninitialized drivers/gpu/drm/i915/intel_display.c: In function ‘intel_modeset_init’: include/drm/drm_atomic.h:224:2: error: ‘state’ may be used uninitialized in this function [-Werror=maybe-uninitialized] This changes the function back to only drop the reference count when it was successfully allocated first. Fixes: 0853695c3ba4 ("drm: Add reference counting to drm_atomic_state") Cc: Chris Wilson Cc: Daniel Vetter Signed-off-by: Arnd Bergmann Reviewed-by: Eric Engestrom Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161018151652.2690201-1-arnd@arndb.de --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a12e093c54cf..1e3b5eebd2a2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -16294,7 +16294,7 @@ retry: * BIOS-programmed watermarks untouched and hope for the best. */ WARN(true, "Could not determine valid watermarks for inherited state\n"); - goto fail; + goto put_state; } /* Write calculated watermark values back */ @@ -16305,8 +16305,9 @@ retry: dev_priv->display.optimize_watermarks(cs); } -fail: +put_state: drm_atomic_state_put(state); +fail: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); } From fb80016af071b3baedb8c2f327ae599f8ab107dc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 18 Oct 2016 13:57:19 -0700 Subject: [PATCH 40/55] gpu: Remove depends on RESET_CONTROLLER when not a provider These GPU drivers only depend on the RESET_CONTROLLER config option to fix build issues that existed when there weren't stub reset APIs for reset controller consumers. Given that these drivers aren't providing any reset controllers themselves, they don't actually depend on the API to build (just to function) so they don't need to depend on it. Remove the dependency to fix recursive build errors like the following: drivers/usb/Kconfig:39:error: recursive dependency detected! drivers/usb/Kconfig:39: symbol USB is selected by MOUSE_APPLETOUCH drivers/input/mouse/Kconfig:187: symbol MOUSE_APPLETOUCH depends on INPUT drivers/input/Kconfig:8: symbol INPUT is selected by VT drivers/tty/Kconfig:12: symbol VT is selected by FB_STI drivers/video/fbdev/Kconfig:674: symbol FB_STI depends on FB drivers/video/fbdev/Kconfig:5: symbol FB is selected by DRM_KMS_FB_HELPER drivers/gpu/drm/Kconfig:42: symbol DRM_KMS_FB_HELPER is selected by DRM_KMS_CMA_HELPER drivers/gpu/drm/Kconfig:98: symbol DRM_KMS_CMA_HELPER is selected by DRM_IMX drivers/gpu/drm/imx/Kconfig:1: symbol DRM_IMX depends on IMX_IPUV3_CORE drivers/gpu/ipu-v3/Kconfig:1: symbol IMX_IPUV3_CORE depends on RESET_CONTROLLER drivers/reset/Kconfig:4: symbol RESET_CONTROLLER is selected by USB_CHIPIDEA drivers/usb/chipidea/Kconfig:1: symbol USB_CHIPIDEA depends on USB_EHCI_HCD drivers/usb/host/Kconfig:84: symbol USB_EHCI_HCD depends on USB Cc: Arnd Bergmann Cc: Cc: Heiko Stuebner Cc: Mark Yao Acked-by: Philipp Zabel Acked-by: robdclark@gmail.com Signed-off-by: Stephen Boyd Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161018205719.20575-1-stephen.boyd@linaro.org --- drivers/gpu/drm/rockchip/Kconfig | 1 - drivers/gpu/drm/tegra/Kconfig | 1 - drivers/gpu/ipu-v3/Kconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 3c58669a06ce..6f7f9c59f05b 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -1,7 +1,6 @@ config DRM_ROCKCHIP tristate "DRM Support for Rockchip" depends on DRM && ROCKCHIP_IOMMU - depends on RESET_CONTROLLER select DRM_GEM_CMA_HELPER select DRM_KMS_HELPER select DRM_PANEL diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 63ebb154b9b5..bbf5a4b7e0b6 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -3,7 +3,6 @@ config DRM_TEGRA depends on ARCH_TEGRA || (ARM && COMPILE_TEST) depends on COMMON_CLK depends on DRM - depends on RESET_CONTROLLER select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig index aefdff95356d..08766c6e7856 100644 --- a/drivers/gpu/ipu-v3/Kconfig +++ b/drivers/gpu/ipu-v3/Kconfig @@ -1,7 +1,6 @@ config IMX_IPUV3_CORE tristate "IPUv3 core support" depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM - depends on RESET_CONTROLLER select GENERIC_IRQ_CHIP help Choose this if you have a i.MX5/6 system and want to use the Image From e3f56b2953ec8160629295bc2be0c8d3b8f4d1d3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 18 Oct 2016 14:28:35 +0300 Subject: [PATCH 41/55] drm: fix sparse warnings on undeclared symbols in crc debugfs Fixes sparse warnings: drivers/gpu/drm/drm_debugfs_crc.c:118:30: warning: symbol 'drm_crtc_crc_control_fops' was not declared. Should it be static? drivers/gpu/drm/drm_debugfs_crc.c:264:30: warning: symbol 'drm_crtc_crc_data_fops' was not declared. Should it be static? drivers/gpu/drm/drm_debugfs_crc.c:281:5: warning: symbol 'drm_debugfs_crtc_crc_add' was not declared. Should it be static? Fixes: 9edbf1fa600a ("drm: Add API for capturing frame CRCs") Cc: Benjamin Gaignard Cc: Daniel Vetter Cc: Emil Velikov Cc: Tomeu Vizoso Reviewed-by: Chris Wilson Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1476790115-28665-1-git-send-email-jani.nikula@intel.com --- drivers/gpu/drm/drm_debugfs_crc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 4129405d17c0..00e771fb7df2 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -30,6 +30,7 @@ #include #include #include +#include "drm_internal.h" /** * DOC: CRC ABI @@ -115,7 +116,7 @@ static ssize_t crc_control_write(struct file *file, const char __user *ubuf, return len; } -const struct file_operations drm_crtc_crc_control_fops = { +static const struct file_operations drm_crtc_crc_control_fops = { .owner = THIS_MODULE, .open = crc_control_open, .read = seq_read, @@ -261,7 +262,7 @@ static ssize_t crtc_crc_read(struct file *filep, char __user *user_buf, return LINE_LEN(crc->values_cnt); } -const struct file_operations drm_crtc_crc_data_fops = { +static const struct file_operations drm_crtc_crc_data_fops = { .owner = THIS_MODULE, .open = crtc_crc_open, .read = crtc_crc_read, From 41b9bb1b3be4cf6b9c28bbe1223744de48bf25c0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 19 Oct 2016 17:32:19 -0700 Subject: [PATCH 42/55] drm/fb_cma_helper: do not free fbdev if there is none If fbdev emulation is not in use (or not built-in), fb_helper.fbdev is NULL. Don't call calling drm_fbdev_cma_defio_fini in this case. Signed-off-by: Stefan Agner Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161020003221.2941-2-stefan@agner.ch --- drivers/gpu/drm/drm_fb_cma_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index fac4f06f8485..4c6664407bfb 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -560,7 +560,8 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) { drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); - drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); + if (fbdev_cma->fb_helper.fbdev) + drm_fbdev_cma_defio_fini(fbdev_cma->fb_helper.fbdev); drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); if (fbdev_cma->fb) { From 7fb71c8f4f45afe73d307181be87c877447d0e47 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 19 Oct 2016 12:37:43 +0100 Subject: [PATCH 43/55] drm/i915: Handle early failure during intel_get_load_detect_pipe In the error path, we have to be ready to handle an error before either the state or restore_state have been allocated. [ 397.001342] BUG: unable to handle kernel NULL pointer dereference at (null) [ 397.001419] IP: [] intel_get_load_detect_pipe+0xe4/0x610 [i915] [ 397.001502] PGD 136a2a067 [ 397.001523] PUD 134b5f067 [ 397.001546] PMD 0 [ 397.001569] Oops: 0002 [#1] PREEMPT SMP [ 397.001599] Modules linked in: snd_hda_intel i915 cdc_ncm usbnet mii x86_pkg_temp_thermal intel_powerclamp coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_codec snd_hwdep snd_hda_core snd_pcm lpc_ich mei_me mei sdhci_pci sdhci mmc_core e1000e ptp pps_core [last unloaded: i915] [ 397.001902] CPU: 1 PID: 9287 Comm: kms_force_conne Tainted: G U 4.9.0-rc1-CI-CI_DRM_1730+ #1 [ 397.001965] Hardware name: LENOVO 2356GCG/2356GCG, BIOS G7ET31WW (1.13 ) 07/02/2012 [ 397.002017] task: ffff880138c38040 task.stack: ffffc900083e4000 [ 397.002057] RIP: 0010:[] [] intel_get_load_detect_pipe+0xe4/0x610 [i915] [ 397.002153] RSP: 0018:ffffc900083e7ae8 EFLAGS: 00010286 [ 397.002191] RAX: 00000000ffffffdd RBX: ffffc900083e7bc8 RCX: 0000000000000006 [ 397.002239] RDX: 0000000000000006 RSI: ffff880138c388b8 RDI: ffffc900083e79e0 [ 397.002287] RBP: ffffc900083e7b78 R08: 0000000000000000 R09: 0000000000000000 [ 397.002335] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 [ 397.002386] R13: ffff8801305e1158 R14: 00000000ffffffdd R15: 0000000000000000 [ 397.002434] FS: 00007fea1b03c740(0000) GS:ffff88013e240000(0000) knlGS:0000000000000000 [ 397.002488] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 397.002528] CR2: 0000000000000000 CR3: 00000001361da000 CR4: 00000000001406e0 [ 397.002576] Stack: [ 397.002592] ffff88013046f180 0000000000000000 ffffc900083e7bc0 0000000000000000 [ 397.002655] 0000000000000000 ffff8801306bd038 ffff88012e980000 ffffc90000000001 [ 397.002718] ffffc90000000000 ffff880136b8ca88 ffff88012e980890 ffff88012e980540 [ 397.002780] Call Trace: [ 397.002828] [] intel_crt_detect+0x3c4/0x8f0 [i915] [ 397.002876] [] ? vprintk_default+0x1a/0x20 [ 397.002918] [] ? printk+0x43/0x4b [ 397.002956] [] drm_helper_probe_single_connector_modes+0x406/0x4f0 [ 397.003014] [] ? mutex_unlock+0x9/0x10 [ 397.003054] [] drm_mode_getconnector+0x33c/0x3c0 [ 397.003099] [] ? debug_lockdep_rcu_enabled+0x1d/0x20 [ 397.003147] [] ? __might_fault+0x3e/0x90 [ 397.003191] [] drm_ioctl+0x1f6/0x480 [ 397.003231] [] ? drm_mode_connector_property_set_ioctl+0x30/0x30 [ 397.003285] [] do_vfs_ioctl+0x8e/0x690 [ 397.003324] [] ? task_work_run+0x8c/0xb0 [ 397.003366] [] ? trace_hardirqs_on_caller+0x122/0x1b0 [ 397.003412] [] SyS_ioctl+0x3c/0x70 [ 397.003451] [] entry_SYSCALL_64_fastpath+0x1c/0xb1 [ 397.003496] Code: 85 c0 41 89 c6 75 57 49 8b 85 f0 00 00 00 48 89 de 45 31 ff 48 8d 78 20 e8 1a 89 13 e1 45 31 c9 85 c0 41 89 c6 0f 84 2f 01 00 00 41 83 29 01 74 53 f0 41 83 2f 01 74 2d 41 83 fe dd 75 35 48 [ 397.003837] RIP [] intel_get_load_detect_pipe+0xe4/0x610 [i915] [ 397.003921] RSP [ 397.003947] CR2: 0000000000000000 Testcase: igt/kms_force_connector_basic/force-load-detect # ivb-3720m Fixes: 0853695c3ba4 ("drm: Add reference counting to drm_atomic_state" Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161019113743.19847-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/i915/intel_display.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e3b5eebd2a2..e11896cd2015 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11251,9 +11251,14 @@ found: return true; fail: - drm_atomic_state_put(state); - drm_atomic_state_put(restore_state); - restore_state = state = NULL; + if (state) { + drm_atomic_state_put(state); + state = NULL; + } + if (restore_state) { + drm_atomic_state_put(restore_state); + restore_state = NULL; + } if (ret == -EDEADLK) { drm_modeset_backoff(ctx); From 838de39fc9516470b1410cc068c7f41daec69265 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 20 Oct 2016 12:50:03 -0200 Subject: [PATCH 44/55] drm/fence: release fence reference when canceling event If the event gets canceled we also need to put away the fence reference it holds. Signed-off-by: Gustavo Padovan Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1476975005-30441-3-git-send-email-gustavo@padovan.org --- drivers/gpu/drm/drm_fops.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index e84faecf5225..8bed5f459182 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -663,6 +663,10 @@ void drm_event_cancel_free(struct drm_device *dev, list_del(&p->pending_link); } spin_unlock_irqrestore(&dev->event_lock, flags); + + if (p->fence) + fence_put(p->fence); + kfree(p); } EXPORT_SYMBOL(drm_event_cancel_free); From de1e211ff7b948b286222f592a5168746a7dc5e5 Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Sat, 8 Oct 2016 08:55:18 +0100 Subject: [PATCH 45/55] drm/virtio: kconfig: Fixup white space. Use tabs instead of spaces. Signed-off-by: Peter Griffin Acked-by: Lee Jones Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1475913318-12275-1-git-send-email-peter.griffin@linaro.org Link: http://patchwork.freedesktop.org/patch/msgid/1476238699-25820-1-git-send-email-jiang.biao2@zte.com.cn --- drivers/gpu/drm/virtio/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/virtio/Kconfig b/drivers/gpu/drm/virtio/Kconfig index e1afc3d3f8d9..81d1807ac228 100644 --- a/drivers/gpu/drm/virtio/Kconfig +++ b/drivers/gpu/drm/virtio/Kconfig @@ -1,10 +1,10 @@ config DRM_VIRTIO_GPU tristate "Virtio GPU driver" depends on DRM && VIRTIO - select DRM_KMS_HELPER - select DRM_TTM + select DRM_KMS_HELPER + select DRM_TTM help This is the virtual GPU driver for virtio. It can be used with - QEMU based VMMs (like KVM or Xen). + QEMU based VMMs (like KVM or Xen). If unsure say M. From 30cd85dd6edc86ea8d8589efb813f1fad41ef233 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 19 Oct 2016 15:48:32 -0200 Subject: [PATCH 46/55] dma-buf/sync_file: hold reference to fence when creating sync_file fence referencing was out of balance. It was not taking any ref to the fence at creating time, but it was putting a reference when freeing the sync file. This patch fixes the balancing issue by getting a reference for the fence when creating the sync_file. Signed-off-by: Gustavo Padovan Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1476899313-22241-1-git-send-email-gustavo@padovan.org --- drivers/dma-buf/sync_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index b29a9e817320..235f8ac113cc 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -79,7 +79,7 @@ struct sync_file *sync_file_create(struct fence *fence) if (!sync_file) return NULL; - sync_file->fence = fence; + sync_file->fence = fence_get(fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence), From bd2ef25d921c0d937e4bc4f5a4f98f534424c6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:46 +0300 Subject: [PATCH 47/55] drm: Add drm_rotation_90_or_270() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have intel_rotation_90_or_270() in i915 to check if the rotation is 90 or 270 degrees. Similar checks are elsewhere in drm, so let's move the helper into a central place and use it everwhere. v2: Drop the BIT() Convert all new intel_rotation_90_or_270() calls Deal with superfluous code shuffling Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson (v1) Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-2-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 4 ++-- drivers/gpu/drm/drm_atomic_helper.c | 2 +- drivers/gpu/drm/drm_crtc.c | 3 +-- drivers/gpu/drm/i915/intel_atomic_plane.c | 3 ++- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 6 ------ drivers/gpu/drm/i915/intel_fbc.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 12 ++++++------ drivers/gpu/drm/omapdrm/omap_plane.c | 8 ++------ include/drm/drm_blend.h | 5 +++++ 10 files changed, 28 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 9d4c030672f0..b380179d4013 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -393,7 +393,7 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 || state->base.fb->pixel_format == DRM_FORMAT_NV61) && - (state->base.rotation & (DRM_ROTATE_90 | DRM_ROTATE_270))) + drm_rotation_90_or_270(state->base.rotation)) cfg |= ATMEL_HLCDC_YUV422ROT; atmel_hlcdc_layer_update_cfg(&plane->layer, @@ -628,7 +628,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, /* * Swap width and size in case of 90 or 270 degrees rotation */ - if (state->base.rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)) { + if (drm_rotation_90_or_270(state->base.rotation)) { tmp = state->crtc_w; state->crtc_w = state->crtc_h; state->crtc_h = tmp; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 07b432f43b98..f9362760bfb2 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2399,7 +2399,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, primary_state->crtc_h = vdisplay; primary_state->src_x = set->x << 16; primary_state->src_y = set->y << 16; - if (primary_state->rotation & (DRM_ROTATE_90 | DRM_ROTATE_270)) { + if (drm_rotation_90_or_270(primary_state->rotation)) { primary_state->src_w = vdisplay << 16; primary_state->src_h = hdisplay << 16; } else { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 60403bf7a4ff..13441e21117c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -727,8 +727,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); if (crtc->state && - crtc->primary->state->rotation & (DRM_ROTATE_90 | - DRM_ROTATE_270)) + drm_rotation_90_or_270(crtc->primary->state->rotation)) swap(hdisplay, vdisplay); return drm_framebuffer_check_src_coords(x << 16, y << 16, diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index b82de3072d4f..c762ae549a1c 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -142,8 +142,9 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->clip.y2 = crtc_state->base.enable ? crtc_state->pipe_src_h : 0; - if (state->fb && intel_rotation_90_or_270(state->rotation)) { + if (state->fb && drm_rotation_90_or_270(state->rotation)) { char *format_name; + if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e11896cd2015..af18e2cce34b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2139,7 +2139,7 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, const struct drm_framebuffer *fb, unsigned int rotation) { - if (intel_rotation_90_or_270(rotation)) { + if (drm_rotation_90_or_270(rotation)) { *view = i915_ggtt_view_rotated; view->params.rotated = to_intel_framebuffer(fb)->rot_info; } else { @@ -2260,7 +2260,7 @@ void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation) static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane, unsigned int rotation) { - if (intel_rotation_90_or_270(rotation)) + if (drm_rotation_90_or_270(rotation)) return to_intel_framebuffer(fb)->rotated[plane].pitch; else return fb->pitches[plane]; @@ -2296,7 +2296,7 @@ void intel_add_fb_offsets(int *x, int *y, const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb); unsigned int rotation = state->base.rotation; - if (intel_rotation_90_or_270(rotation)) { + if (drm_rotation_90_or_270(rotation)) { *x += intel_fb->rotated[plane].x; *y += intel_fb->rotated[plane].y; } else { @@ -2360,7 +2360,7 @@ static u32 intel_adjust_tile_offset(int *x, int *y, intel_tile_dims(dev_priv, &tile_width, &tile_height, fb->modifier[plane], cpp); - if (intel_rotation_90_or_270(rotation)) { + if (drm_rotation_90_or_270(rotation)) { pitch_tiles = pitch / tile_height; swap(tile_width, tile_height); } else { @@ -2416,7 +2416,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, intel_tile_dims(dev_priv, &tile_width, &tile_height, fb_modifier, cpp); - if (intel_rotation_90_or_270(rotation)) { + if (drm_rotation_90_or_270(rotation)) { pitch_tiles = pitch / tile_height; swap(tile_width, tile_height); } else { @@ -2976,7 +2976,7 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state) int ret; /* Rotate src coordinates to match rotated GTT view */ - if (intel_rotation_90_or_270(rotation)) + if (drm_rotation_90_or_270(rotation)) drm_rect_rotate(&plane_state->base.src, fb->width, fb->height, DRM_ROTATE_270); @@ -3276,7 +3276,7 @@ u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, * The stride is either expressed as a multiple of 64 bytes chunks for * linear buffers or in number of tiles for tiled buffers. */ - if (intel_rotation_90_or_270(rotation)) { + if (drm_rotation_90_or_270(rotation)) { int cpp = drm_format_plane_cpp(fb->pixel_format, plane); stride /= intel_tile_height(dev_priv, fb->modifier[0], cpp); @@ -4666,7 +4666,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, to_intel_crtc(crtc_state->base.crtc); int need_scaling; - need_scaling = intel_rotation_90_or_270(rotation) ? + need_scaling = drm_rotation_90_or_270(rotation) ? (src_h != dst_w || src_w != dst_h): (src_w != dst_w || src_h != dst_h); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8fd16adf069b..c6ae525fe1f5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1284,12 +1284,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, unsigned int intel_tile_height(const struct drm_i915_private *dev_priv, uint64_t fb_modifier, unsigned int cpp); -static inline bool -intel_rotation_90_or_270(unsigned int rotation) -{ - return rotation & (DRM_ROTATE_90 | DRM_ROTATE_270); -} - void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index faa67624e1ed..afc040be1172 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -84,7 +84,7 @@ static void intel_fbc_get_plane_source_size(struct intel_fbc_state_cache *cache, { int w, h; - if (intel_rotation_90_or_270(cache->plane.rotation)) { + if (drm_rotation_90_or_270(cache->plane.rotation)) { w = cache->plane.src_h; h = cache->plane.src_w; } else { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2df06b703e3d..1472400ddce3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3151,7 +3151,7 @@ skl_plane_downscale_amount(const struct intel_plane_state *pstate) src_h = drm_rect_height(&pstate->base.src); dst_w = drm_rect_width(&pstate->base.dst); dst_h = drm_rect_height(&pstate->base.dst); - if (intel_rotation_90_or_270(pstate->base.rotation)) + if (drm_rotation_90_or_270(pstate->base.rotation)) swap(dst_w, dst_h); downscale_h = max(src_h / dst_h, (uint32_t)DRM_PLANE_HELPER_NO_SCALING); @@ -3182,7 +3182,7 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, width = drm_rect_width(&intel_pstate->base.src) >> 16; height = drm_rect_height(&intel_pstate->base.src) >> 16; - if (intel_rotation_90_or_270(pstate->rotation)) + if (drm_rotation_90_or_270(pstate->rotation)) swap(width, height); /* for planar format */ @@ -3282,7 +3282,7 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, src_w = drm_rect_width(&intel_pstate->base.src) >> 16; src_h = drm_rect_height(&intel_pstate->base.src) >> 16; - if (intel_rotation_90_or_270(pstate->rotation)) + if (drm_rotation_90_or_270(pstate->rotation)) swap(src_w, src_h); /* Halve UV plane width and height for NV12 */ @@ -3296,7 +3296,7 @@ skl_ddb_min_alloc(const struct drm_plane_state *pstate, else plane_bpp = drm_format_plane_cpp(fb->pixel_format, 0); - if (intel_rotation_90_or_270(pstate->rotation)) { + if (drm_rotation_90_or_270(pstate->rotation)) { switch (plane_bpp) { case 1: min_scanlines = 32; @@ -3554,7 +3554,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, width = drm_rect_width(&intel_pstate->base.src) >> 16; height = drm_rect_height(&intel_pstate->base.src) >> 16; - if (intel_rotation_90_or_270(pstate->rotation)) + if (drm_rotation_90_or_270(pstate->rotation)) swap(width, height); cpp = drm_format_plane_cpp(fb->pixel_format, 0); @@ -3575,7 +3575,7 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv, fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { uint32_t min_scanlines = 4; uint32_t y_tile_minimum; - if (intel_rotation_90_or_270(pstate->rotation)) { + if (drm_rotation_90_or_270(pstate->rotation)) { int cpp = (fb->pixel_format == DRM_FORMAT_NV12) ? drm_format_plane_cpp(fb->pixel_format, 1) : drm_format_plane_cpp(fb->pixel_format, 0); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 66ac8c40db26..1549e8393056 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -108,16 +108,12 @@ static void omap_plane_atomic_update(struct drm_plane *plane, win.src_x = state->src_x >> 16; win.src_y = state->src_y >> 16; - switch (state->rotation & DRM_ROTATE_MASK) { - case DRM_ROTATE_90: - case DRM_ROTATE_270: + if (drm_rotation_90_or_270(state->rotation)) { win.src_w = state->src_h >> 16; win.src_h = state->src_w >> 16; - break; - default: + } else { win.src_w = state->src_w >> 16; win.src_h = state->src_h >> 16; - break; } /* update scanout: */ diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index 36baa175de99..bb493410396c 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -47,6 +47,11 @@ struct drm_atomic_state; #define DRM_REFLECT_Y BIT(5) #define DRM_REFLECT_MASK (DRM_REFLECT_X | DRM_REFLECT_Y) +static inline bool drm_rotation_90_or_270(unsigned int rotation) +{ + return rotation & (DRM_ROTATE_90 | DRM_ROTATE_270); +} + struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, unsigned int supported_rotations); unsigned int drm_rotation_simplify(unsigned int rotation, From 6e0c7c3358d4e8e9917a97348e6f77da88226cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:47 +0300 Subject: [PATCH 48/55] drm/atomic: Reject attempts to use multiple rotation angles at once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rotation property should only accept exactly one rotation angle at once. Let's reject attempts to set none or multiple angles. Testcase: igt/kms_rotation_crc/bad-rotation Signed-off-by: Ville Syrjälä Reviewed-by: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-3-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 5dd70540219c..13ce95ee458e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -706,6 +706,8 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == config->prop_src_h) { state->src_h = val; } else if (property == config->rotation_property) { + if (!is_power_of_2(val & DRM_ROTATE_MASK)) + return -EINVAL; state->rotation = val; } else if (property == plane->zpos_property) { state->zpos = val; From d138dd3c0c70979215f3184cf36f95875e37932e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:48 +0300 Subject: [PATCH 49/55] drm: Add support for optional per-plane rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all planes on the system may support the same rotations/reflections, so make it possible to create a separate property for each plane. This way userspace gets told exactly which rotations/reflections are possible for each plane. v2: Add drm_plane_create_rotation_property() helper v3: Drop the BIT(), __builtin_ffs(x) - 1, Moar WARNs for bad parameters Deal with superfluous code shuffling Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson (v1) Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-4-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_atomic.c | 6 ++++-- drivers/gpu/drm/drm_blend.c | 35 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_fb_helper.c | 6 +++++- include/drm/drm_blend.h | 3 +++ include/drm/drm_plane.h | 2 ++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 13ce95ee458e..f81706387889 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -705,7 +705,8 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, state->src_w = val; } else if (property == config->prop_src_h) { state->src_h = val; - } else if (property == config->rotation_property) { + } else if (property == config->rotation_property || + property == plane->rotation_property) { if (!is_power_of_2(val & DRM_ROTATE_MASK)) return -EINVAL; state->rotation = val; @@ -765,7 +766,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->src_w; } else if (property == config->prop_src_h) { *val = state->src_h; - } else if (property == config->rotation_property) { + } else if (property == config->rotation_property || + property == plane->rotation_property) { *val = state->rotation; } else if (property == plane->zpos_property) { *val = state->zpos; diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 85172a977bf3..e52aece30900 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -162,6 +162,41 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_create_rotation_property); +int drm_plane_create_rotation_property(struct drm_plane *plane, + unsigned int rotation, + unsigned int supported_rotations) +{ + static const struct drm_prop_enum_list props[] = { + { __builtin_ffs(DRM_ROTATE_0) - 1, "rotate-0" }, + { __builtin_ffs(DRM_ROTATE_90) - 1, "rotate-90" }, + { __builtin_ffs(DRM_ROTATE_180) - 1, "rotate-180" }, + { __builtin_ffs(DRM_ROTATE_270) - 1, "rotate-270" }, + { __builtin_ffs(DRM_REFLECT_X) - 1, "reflect-x" }, + { __builtin_ffs(DRM_REFLECT_Y) - 1, "reflect-y" }, + }; + struct drm_property *prop; + + WARN_ON((supported_rotations & DRM_ROTATE_MASK) == 0); + WARN_ON(!is_power_of_2(rotation & DRM_ROTATE_MASK)); + WARN_ON(rotation & ~supported_rotations); + + prop = drm_property_create_bitmask(plane->dev, 0, "rotation", + props, ARRAY_SIZE(props), + supported_rotations); + if (!prop) + return -ENOMEM; + + drm_object_attach_property(&plane->base, prop, rotation); + + if (plane->state) + plane->state->rotation = rotation; + + plane->rotation_property = prop; + + return 0; +} +EXPORT_SYMBOL(drm_plane_create_rotation_property); + /** * drm_rotation_simplify() - Try to simplify the rotation * @rotation: Rotation to be simplified diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 8fffac8c5c75..e0d428f9d1cb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -392,7 +392,11 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); - if (dev->mode_config.rotation_property) { + if (plane->rotation_property) { + drm_mode_plane_set_obj_prop(plane, + plane->rotation_property, + DRM_ROTATE_0); + } else if (dev->mode_config.rotation_property) { drm_mode_plane_set_obj_prop(plane, dev->mode_config.rotation_property, DRM_ROTATE_0); diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h index bb493410396c..fd351924e1c5 100644 --- a/include/drm/drm_blend.h +++ b/include/drm/drm_blend.h @@ -54,6 +54,9 @@ static inline bool drm_rotation_90_or_270(unsigned int rotation) struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, unsigned int supported_rotations); +int drm_plane_create_rotation_property(struct drm_plane *plane, + unsigned int rotation, + unsigned int supported_rotations); unsigned int drm_rotation_simplify(unsigned int rotation, unsigned int supported_rotations); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 02353904cdba..98b39d66eb32 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -385,6 +385,7 @@ enum drm_plane_type { * @type: type of plane (overlay, primary, cursor) * @state: current atomic state for this plane * @zpos_property: zpos property for this plane + * @rotation_property: rotation property for this plane * @helper_private: mid-layer private data */ struct drm_plane { @@ -431,6 +432,7 @@ struct drm_plane { struct drm_plane_state *state; struct drm_property *zpos_property; + struct drm_property *rotation_property; }; #define obj_to_plane(x) container_of(x, struct drm_plane, base) From ea0e1ce20f736ee7e9209fec2f78880a06056890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:49 +0300 Subject: [PATCH 50/55] drm/arm: Use per-plane rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The global mode_config.rotation_property is going away, switch over to per-plane rotation_property. v2: Drop the BIT() Cc: Liviu Dudau Cc: Brian Starkey Cc: Mali DP Maintainers Signed-off-by: Ville Syrjälä Acked-by: Brian Starkey Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-5-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/arm/malidp_planes.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 82c193e5e0d6..abaca03b9d36 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -254,21 +254,18 @@ int malidp_de_planes_init(struct drm_device *drm) if (ret < 0) goto cleanup; - if (!drm->mode_config.rotation_property) { + /* SMART layer can't be rotated */ + if (id != DE_SMART) { unsigned long flags = DRM_ROTATE_0 | DRM_ROTATE_90 | DRM_ROTATE_180 | DRM_ROTATE_270 | DRM_REFLECT_X | DRM_REFLECT_Y; - drm->mode_config.rotation_property = - drm_mode_create_rotation_property(drm, flags); + drm_plane_create_rotation_property(&plane->base, + DRM_ROTATE_0, + flags); } - /* SMART layer can't be rotated */ - if (drm->mode_config.rotation_property && (id != DE_SMART)) - drm_object_attach_property(&plane->base.base, - drm->mode_config.rotation_property, - DRM_ROTATE_0); drm_plane_helper_add(&plane->base, &malidp_de_plane_helper_funcs); From 9fe58f017b54e4d3457479c258d7a8466fc1655e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:50 +0300 Subject: [PATCH 51/55] drm/atmel-hlcdc: Use per-plane rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The global mode_config.rotation_property is going away, switch over to per-plane rotation_property. v2: Propagate error upwards (Boris) v3: Drop the BIT() Cc: Boris Brezillon Signed-off-by: Ville Syrjälä Acked-by: Boris Brezillon Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-6-git-send-email-ville.syrjala@linux.intel.com --- .../gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index b380179d4013..246ed1e33d8a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c @@ -883,9 +883,9 @@ static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p, return 0; } -static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, - const struct atmel_hlcdc_layer_desc *desc, - struct atmel_hlcdc_plane_properties *props) +static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, + const struct atmel_hlcdc_layer_desc *desc, + struct atmel_hlcdc_plane_properties *props) { struct regmap *regmap = plane->layer.hlcdc->regmap; @@ -902,10 +902,18 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, ATMEL_HLCDC_LAYER_GA_MASK); } - if (desc->layout.xstride && desc->layout.pstride) - drm_object_attach_property(&plane->base.base, - plane->base.dev->mode_config.rotation_property, - DRM_ROTATE_0); + if (desc->layout.xstride && desc->layout.pstride) { + int ret; + + ret = drm_plane_create_rotation_property(&plane->base, + DRM_ROTATE_0, + DRM_ROTATE_0 | + DRM_ROTATE_90 | + DRM_ROTATE_180 | + DRM_ROTATE_270); + if (ret) + return ret; + } if (desc->layout.csc) { /* @@ -925,6 +933,8 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2), 0x40040890); } + + return 0; } static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { @@ -1036,7 +1046,9 @@ atmel_hlcdc_plane_create(struct drm_device *dev, &atmel_hlcdc_layer_plane_helper_funcs); /* Set default property values*/ - atmel_hlcdc_plane_init_properties(plane, desc, props); + ret = atmel_hlcdc_plane_init_properties(plane, desc, props); + if (ret) + return ERR_PTR(ret); return plane; } @@ -1054,15 +1066,6 @@ atmel_hlcdc_plane_create_properties(struct drm_device *dev) if (!props->alpha) return ERR_PTR(-ENOMEM); - dev->mode_config.rotation_property = - drm_mode_create_rotation_property(dev, - DRM_ROTATE_0 | - DRM_ROTATE_90 | - DRM_ROTATE_180 | - DRM_ROTATE_270); - if (!dev->mode_config.rotation_property) - return ERR_PTR(-ENOMEM); - return props; } From 18391ec0bb4a1ea1ba2b485b8b29ac536d52fa5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:51 +0300 Subject: [PATCH 52/55] drm/omap: Set rotation property initial value to BIT(DRM_ROTATE_0) insted of 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0 isn't a valid rotation property value, so let's set the initial value of the property to BIT(DRM_ROTATE_0) instead. v2: Drop the BIT() Cc: Tomi Valkeinen Cc: Rob Clark Signed-off-by: Ville Syrjälä Reviewed-by: Tomi Valkeinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-7-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/omapdrm/omap_drv.c | 6 ++++-- drivers/gpu/drm/omapdrm/omap_plane.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 1735c7accf72..31ec5d0a9576 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -762,12 +762,14 @@ static void dev_lastclose(struct drm_device *dev) */ for (i = 0; i < priv->num_crtcs; i++) { drm_object_property_set_value(&priv->crtcs[i]->base, - dev->mode_config.rotation_property, 0); + dev->mode_config.rotation_property, + DRM_ROTATE_0); } for (i = 0; i < priv->num_planes; i++) { drm_object_property_set_value(&priv->planes[i]->base, - dev->mode_config.rotation_property, 0); + dev->mode_config.rotation_property, + DRM_ROTATE_0); } } diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 1549e8393056..6ddaa5ea4b6b 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -213,7 +213,7 @@ void omap_plane_install_properties(struct drm_plane *plane, if (priv->has_dmm) { struct drm_property *prop = dev->mode_config.rotation_property; - drm_object_attach_property(obj, prop, 0); + drm_object_attach_property(obj, prop, DRM_ROTATE_0); } drm_object_attach_property(obj, priv->zorder_prop, 0); From 0da88db14034e8b309f1c4188123ca1a02f4b354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:52 +0300 Subject: [PATCH 53/55] drm/omap: Use per-plane rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The global mode_config.rotation_property is going away, switch over to per-plane rotation_property. Not sure I got the annoying crtc rotation_property handling right. Might work, or migth not. v2: Drop the BIT() Don't create rotation property twice for each primary plane Cc: Tomi Valkeinen Cc: Rob Clark Signed-off-by: Ville Syrjälä Reviewed-by: Tomi Valkeinen [danvet: Add comment per discussion between Tomi&Ville.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-8-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/omapdrm/omap_crtc.c | 13 +++---- drivers/gpu/drm/omapdrm/omap_drv.c | 52 +++++++++++++--------------- drivers/gpu/drm/omapdrm/omap_plane.c | 12 +++++-- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 180f644e861e..16c691dbc372 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -438,13 +438,14 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, } } -static bool omap_crtc_is_plane_prop(struct drm_device *dev, +static bool omap_crtc_is_plane_prop(struct drm_crtc *crtc, struct drm_property *property) { + struct drm_device *dev = crtc->dev; struct omap_drm_private *priv = dev->dev_private; return property == priv->zorder_prop || - property == dev->mode_config.rotation_property; + property == crtc->primary->rotation_property; } static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, @@ -452,9 +453,7 @@ static int omap_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t val) { - struct drm_device *dev = crtc->dev; - - if (omap_crtc_is_plane_prop(dev, property)) { + if (omap_crtc_is_plane_prop(crtc, property)) { struct drm_plane_state *plane_state; struct drm_plane *plane = crtc->primary; @@ -479,9 +478,7 @@ static int omap_crtc_atomic_get_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t *val) { - struct drm_device *dev = crtc->dev; - - if (omap_crtc_is_plane_prop(dev, property)) { + if (omap_crtc_is_plane_prop(crtc, property)) { /* * Delegate property get to the primary plane. The * drm_atomic_plane_get_property() function isn't exported, but diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 31ec5d0a9576..39c5312b466c 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -293,16 +293,6 @@ static int omap_modeset_init_properties(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; - if (priv->has_dmm) { - dev->mode_config.rotation_property = - drm_mode_create_rotation_property(dev, - DRM_ROTATE_0 | DRM_ROTATE_90 | - DRM_ROTATE_180 | DRM_ROTATE_270 | - DRM_REFLECT_X | DRM_REFLECT_Y); - if (!dev->mode_config.rotation_property) - return -ENOMEM; - } - priv->zorder_prop = drm_property_create_range(dev, 0, "zorder", 0, 3); if (!priv->zorder_prop) return -ENOMEM; @@ -753,24 +743,32 @@ static void dev_lastclose(struct drm_device *dev) DBG("lastclose: dev=%p", dev); - if (dev->mode_config.rotation_property) { - /* need to restore default rotation state.. not sure - * if there is a cleaner way to restore properties to - * default state? Maybe a flag that properties should - * automatically be restored to default state on - * lastclose? - */ - for (i = 0; i < priv->num_crtcs; i++) { - drm_object_property_set_value(&priv->crtcs[i]->base, - dev->mode_config.rotation_property, - DRM_ROTATE_0); - } + /* need to restore default rotation state.. not sure + * if there is a cleaner way to restore properties to + * default state? Maybe a flag that properties should + * automatically be restored to default state on + * lastclose? + */ + for (i = 0; i < priv->num_crtcs; i++) { + struct drm_crtc *crtc = priv->crtcs[i]; - for (i = 0; i < priv->num_planes; i++) { - drm_object_property_set_value(&priv->planes[i]->base, - dev->mode_config.rotation_property, - DRM_ROTATE_0); - } + if (!crtc->primary->rotation_property) + continue; + + drm_object_property_set_value(&crtc->base, + crtc->primary->rotation_property, + DRM_ROTATE_0); + } + + for (i = 0; i < priv->num_planes; i++) { + struct drm_plane *plane = priv->planes[i]; + + if (!plane->rotation_property) + continue; + + drm_object_property_set_value(&plane->base, + plane->rotation_property, + DRM_ROTATE_0); } if (priv->fbdev) { diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 6ddaa5ea4b6b..0ffd5b930ec0 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -211,9 +211,17 @@ void omap_plane_install_properties(struct drm_plane *plane, struct omap_drm_private *priv = dev->dev_private; if (priv->has_dmm) { - struct drm_property *prop = dev->mode_config.rotation_property; + if (!plane->rotation_property) + drm_plane_create_rotation_property(plane, + DRM_ROTATE_0, + DRM_ROTATE_0 | DRM_ROTATE_90 | + DRM_ROTATE_180 | DRM_ROTATE_270 | + DRM_REFLECT_X | DRM_REFLECT_Y); - drm_object_attach_property(obj, prop, DRM_ROTATE_0); + /* Attach the rotation property also to the crtc object */ + if (plane->rotation_property && obj != &plane->base) + drm_object_attach_property(obj, plane->rotation_property, + DRM_ROTATE_0); } drm_object_attach_property(obj, priv->zorder_prop, 0); From 93ca7e00667063a8dc86f04373e85e89a09efef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 26 Sep 2016 19:30:56 +0300 Subject: [PATCH 54/55] drm/i915: Use the per-plane rotation property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On certain platforms not all planes support the same set of rotations/reflections, so let's use the per-plane property for this. This is already a problem on SKL when we use the legay cursor plane as it only supports 0|180 whereas the universal planes support 0|90|180|270, and it will be a problem on CHV soon. v2: Use drm_plane_create_rotation_property() helper v3: Drop the BIT(), use INTEL_GEN() Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson (v1) Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1474907460-10717-12-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 52 +++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 3 -- drivers/gpu/drm/i915/intel_sprite.c | 14 +++++++- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af18e2cce34b..6c5c36eba6cb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14886,6 +14886,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, struct intel_plane *primary = NULL; struct intel_plane_state *state = NULL; const uint32_t *intel_primary_formats; + unsigned int supported_rotations; unsigned int num_formats; int ret; @@ -14958,8 +14959,21 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, if (ret) goto fail; - if (INTEL_INFO(dev)->gen >= 4) - intel_create_rotation_property(dev, primary); + if (INTEL_GEN(dev) >= 9) { + supported_rotations = + DRM_ROTATE_0 | DRM_ROTATE_90 | + DRM_ROTATE_180 | DRM_ROTATE_270; + } else if (INTEL_GEN(dev) >= 4) { + supported_rotations = + DRM_ROTATE_0 | DRM_ROTATE_180; + } else { + supported_rotations = DRM_ROTATE_0; + } + + if (INTEL_GEN(dev) >= 4) + drm_plane_create_rotation_property(&primary->base, + DRM_ROTATE_0, + supported_rotations); drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs); @@ -14972,24 +14986,6 @@ fail: return NULL; } -void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane) -{ - if (!dev->mode_config.rotation_property) { - unsigned long flags = DRM_ROTATE_0 | - DRM_ROTATE_180; - - if (INTEL_INFO(dev)->gen >= 9) - flags |= DRM_ROTATE_90 | DRM_ROTATE_270; - - dev->mode_config.rotation_property = - drm_mode_create_rotation_property(dev, flags); - } - if (dev->mode_config.rotation_property) - drm_object_attach_property(&plane->base.base, - dev->mode_config.rotation_property, - plane->base.state->rotation); -} - static int intel_check_cursor_plane(struct drm_plane *plane, struct intel_crtc_state *crtc_state, @@ -15116,17 +15112,11 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, if (ret) goto fail; - if (INTEL_INFO(dev)->gen >= 4) { - if (!dev->mode_config.rotation_property) - dev->mode_config.rotation_property = - drm_mode_create_rotation_property(dev, - DRM_ROTATE_0 | - DRM_ROTATE_180); - if (dev->mode_config.rotation_property) - drm_object_attach_property(&cursor->base.base, - dev->mode_config.rotation_property, - state->base.rotation); - } + if (INTEL_GEN(dev) >= 4) + drm_plane_create_rotation_property(&cursor->base, + DRM_ROTATE_0, + DRM_ROTATE_0 | + DRM_ROTATE_180); if (INTEL_INFO(dev)->gen >=9) state->scaler_id = -1; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c6ae525fe1f5..5145ff264c8e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1284,9 +1284,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, unsigned int intel_tile_height(const struct drm_i915_private *dev_priv, uint64_t fb_modifier, unsigned int cpp); -void intel_create_rotation_property(struct drm_device *dev, - struct intel_plane *plane); - void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index be3e04623e2a..3ea6419e18b9 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1044,6 +1044,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) struct intel_plane_state *state = NULL; unsigned long possible_crtcs; const uint32_t *plane_formats; + unsigned int supported_rotations; int num_plane_formats; int ret; @@ -1119,6 +1120,15 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) goto fail; } + if (INTEL_GEN(dev) >= 9) { + supported_rotations = + DRM_ROTATE_0 | DRM_ROTATE_90 | + DRM_ROTATE_180 | DRM_ROTATE_270; + } else { + supported_rotations = + DRM_ROTATE_0 | DRM_ROTATE_180; + } + intel_plane->pipe = pipe; intel_plane->plane = plane; intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane); @@ -1141,7 +1151,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) if (ret) goto fail; - intel_create_rotation_property(dev, intel_plane); + drm_plane_create_rotation_property(&intel_plane->base, + DRM_ROTATE_0, + supported_rotations); drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); From 8a5bbf327aa16025c78491266a6425807c7fbee0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 21 Oct 2016 15:15:40 +0100 Subject: [PATCH 55/55] drm: Use u64 for intermediate dotclock calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have reached the era where monitor bandwidths now exceed 31bits in frequency calculations, though as we stored them in kHz units we are safe from overflow in the modelines for some time. [ 48.723720] UBSAN: Undefined behaviour in ../drivers/gpu/drm/drm_modes.c:325:49 [ 48.726943] signed integer overflow: [ 48.728503] 2240 * 1000000 cannot be represented in type 'int' Reported-by: Martin Liška Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98372 Signed-off-by: Chris Wilson Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161021141540.26837-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_modes.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 173b7d335834..f64ac86deb84 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -165,6 +165,7 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, unsigned int vfieldrate, hperiod; int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync; int interlace; + u64 tmp; /* allocate the drm_display_mode structure. If failure, we will * return directly @@ -322,8 +323,11 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, drm_mode->vsync_end = drm_mode->vsync_start + vsync; } /* 15/13. Find pixel clock frequency (kHz for xf86) */ - drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod; - drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP; + tmp = drm_mode->htotal; /* perform intermediate calcs in u64 */ + tmp *= HV_FACTOR * 1000; + do_div(tmp, hperiod); + tmp -= drm_mode->clock % CVT_CLOCK_STEP; + drm_mode->clock = tmp; /* 18/16. Find actual vertical frame frequency */ /* ignore - just set the mode flag for interlaced */ if (interlaced) {