From 45fdfdb6475905704134afba3c0ef5f24c2b5921 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 21 Nov 2018 08:17:23 -0500 Subject: [PATCH 01/31] drm/pl111: add of_node_put() of_find_node_by_path() acquires a reference to the node returned by it and that reference needs to be dropped by its caller. Signed-off-by: Yangtao Li Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181121131723.22431-1-tiny.windzz@gmail.com --- drivers/gpu/drm/pl111/pl111_vexpress.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/pl111/pl111_vexpress.c b/drivers/gpu/drm/pl111/pl111_vexpress.c index 5fa0441bb6df..38c938c9adda 100644 --- a/drivers/gpu/drm/pl111/pl111_vexpress.c +++ b/drivers/gpu/drm/pl111/pl111_vexpress.c @@ -55,6 +55,8 @@ int pl111_vexpress_clcd_init(struct device *dev, } } + of_node_put(root); + /* * If there is a coretile HDLCD and it has a driver, * do not mux the CLCD on the motherboard to the DVI. From 7cdf33ab02e01300e7e6289acbac9cd8759f8712 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 28 Nov 2018 11:10:33 +0100 Subject: [PATCH 02/31] drm/vkms: Fix plane duplicate_state We need to handle allocation failures and bail out. While at it, tune the allocation failures down to debug level. syzbot injected an allocation failure and then hit this WARN_ON. Reported-by: syzbot+eb6e5365f23c02517dda@syzkaller.appspotmail.com Signed-off-by: Daniel Vetter Cc: Haneen Mohammed Cc: Sean Paul Cc: Daniel Vetter Cc: Rodrigo Siqueira Cc: Gustavo Padovan Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181128101033.4840-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/vkms/vkms_plane.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 7041007396ae..e3bcea4b4891 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -23,8 +23,11 @@ vkms_plane_duplicate_state(struct drm_plane *plane) return NULL; crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL); - if (WARN_ON(!crc_data)) - DRM_INFO("Couldn't allocate crc_data"); + if (!crc_data) { + DRM_DEBUG_KMS("Couldn't allocate crc_data\n"); + kfree(vkms_state); + return NULL; + } vkms_state->crc_data = crc_data; From 4d55fd66b454c3489758731b7c3f470579c3780e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 28 Nov 2018 16:10:20 +0100 Subject: [PATCH 03/31] drm/virtio: fence: pass plain pointer Since commit "9fdd90c0f4 drm/virtio: add virtio_gpu_alloc_fence()" fences are not allocated any more by virtio_gpu_fence_emit(). So there is no need to pass down a reference to the fence pointer, a plain pointer is enough now. Convert virtio_gpu_fence_emit() and callers. Signed-off-by: Gerd Hoffmann Reviewed-by: Robert Foss Link: http://patchwork.freedesktop.org/patch/msgid/20181128151021.29565-2-kraxel@redhat.com --- drivers/gpu/drm/virtio/virtgpu_drv.h | 14 +++++++------- drivers/gpu/drm/virtio/virtgpu_fence.c | 10 +++++----- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 8 ++++---- drivers/gpu/drm/virtio/virtgpu_plane.c | 2 +- drivers/gpu/drm/virtio/virtgpu_vq.c | 20 ++++++++++---------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 7bec6e36886b..d6cc1a92ca88 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -273,7 +273,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, uint64_t offset, __le32 width, __le32 height, __le32 x, __le32 y, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev, uint32_t resource_id, uint32_t x, uint32_t y, @@ -284,7 +284,7 @@ void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev, uint32_t x, uint32_t y); int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj); int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev); @@ -309,23 +309,23 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev, uint32_t resource_id); void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, void *data, uint32_t data_size, - uint32_t ctx_id, struct virtio_gpu_fence **fence); + uint32_t ctx_id, struct virtio_gpu_fence *fence); void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, uint32_t resource_id, uint32_t ctx_id, uint64_t offset, uint32_t level, struct virtio_gpu_box *box, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, uint32_t ctx_id, uint64_t offset, uint32_t level, struct virtio_gpu_box *box, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, struct virtio_gpu_resource_create_3d *rc_3d, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); void virtio_gpu_fence_ack(struct virtqueue *vq); @@ -358,7 +358,7 @@ struct virtio_gpu_fence *virtio_gpu_fence_alloc( void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence); int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, - struct virtio_gpu_fence **fence); + struct virtio_gpu_fence *fence); void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev, u64 last_seq); diff --git a/drivers/gpu/drm/virtio/virtgpu_fence.c b/drivers/gpu/drm/virtio/virtgpu_fence.c index 6b5d92215cfb..4d6826b27814 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fence.c +++ b/drivers/gpu/drm/virtio/virtgpu_fence.c @@ -91,19 +91,19 @@ void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence) int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, struct virtio_gpu_ctrl_hdr *cmd_hdr, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; unsigned long irq_flags; spin_lock_irqsave(&drv->lock, irq_flags); - (*fence)->seq = ++drv->sync_seq; - dma_fence_get(&(*fence)->f); - list_add_tail(&(*fence)->node, &drv->fences); + fence->seq = ++drv->sync_seq; + dma_fence_get(&fence->f); + list_add_tail(&fence->node, &drv->fences); spin_unlock_irqrestore(&drv->lock, irq_flags); cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE); - cmd_hdr->fence_id = cpu_to_le64((*fence)->seq); + cmd_hdr->fence_id = cpu_to_le64(fence->seq); return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 340f2513d829..e9cdb4c7f654 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -221,7 +221,7 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, } virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, - vfpriv->ctx_id, &out_fence); + vfpriv->ctx_id, out_fence); ttm_eu_fence_buffer_objects(&ticket, &validate_list, &out_fence->f); @@ -349,7 +349,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, } virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL); - ret = virtio_gpu_object_attach(vgdev, qobj, &fence); + ret = virtio_gpu_object_attach(vgdev, qobj, fence); if (ret) { virtio_gpu_fence_cleanup(fence); goto fail_backoff; @@ -450,7 +450,7 @@ static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev, virtio_gpu_cmd_transfer_from_host_3d (vgdev, qobj->hw_res_handle, vfpriv->ctx_id, offset, args->level, - &box, &fence); + &box, fence); reservation_object_add_excl_fence(qobj->tbo.resv, &fence->f); @@ -504,7 +504,7 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data, virtio_gpu_cmd_transfer_to_host_3d (vgdev, qobj, vfpriv ? vfpriv->ctx_id : 0, offset, - args->level, &box, &fence); + args->level, &box, fence); reservation_object_add_excl_fence(qobj->tbo.resv, &fence->f); dma_fence_put(&fence->f); diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index b84ac8c25856..ead5c53d4e21 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -204,7 +204,7 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, (vgdev, bo, 0, cpu_to_le32(plane->state->crtc_w), cpu_to_le32(plane->state->crtc_h), - 0, 0, &vgfb->fence); + 0, 0, vgfb->fence); ret = virtio_gpu_object_reserve(bo, false); if (!ret) { reservation_object_add_excl_fence(bo->tbo.resv, diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 2c6764f08f18..97038662b926 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -298,7 +298,7 @@ static int virtio_gpu_queue_ctrl_buffer(struct virtio_gpu_device *vgdev, static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf, struct virtio_gpu_ctrl_hdr *hdr, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtqueue *vq = vgdev->ctrlq.vq; int rc; @@ -405,7 +405,7 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev, static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev, uint32_t resource_id, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_resource_detach_backing *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -467,7 +467,7 @@ void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev, uint64_t offset, __le32 width, __le32 height, __le32 x, __le32 y, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_transfer_to_host_2d *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -497,7 +497,7 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev, uint32_t resource_id, struct virtio_gpu_mem_entry *ents, uint32_t nents, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_resource_attach_backing *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -821,7 +821,7 @@ void virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, struct virtio_gpu_resource_create_3d *rc_3d, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_resource_create_3d *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -842,7 +842,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, uint32_t ctx_id, uint64_t offset, uint32_t level, struct virtio_gpu_box *box, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_transfer_host_3d *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -870,7 +870,7 @@ void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, uint32_t resource_id, uint32_t ctx_id, uint64_t offset, uint32_t level, struct virtio_gpu_box *box, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { struct virtio_gpu_transfer_host_3d *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -890,7 +890,7 @@ void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, void *data, uint32_t data_size, - uint32_t ctx_id, struct virtio_gpu_fence **fence) + uint32_t ctx_id, struct virtio_gpu_fence *fence) { struct virtio_gpu_cmd_submit *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -910,7 +910,7 @@ void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *obj, - struct virtio_gpu_fence **fence) + struct virtio_gpu_fence *fence) { bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev); struct virtio_gpu_mem_entry *ents; @@ -967,7 +967,7 @@ void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, if (use_dma_api && obj->mapped) { struct virtio_gpu_fence *fence = virtio_gpu_fence_alloc(vgdev); /* detach backing and wait for the host process it ... */ - virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence); + virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, fence); dma_fence_wait(&fence->f, true); dma_fence_put(&fence->f); From d7a86dffc280cb5a2a18975d46c7b9d89b025c7e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 28 Nov 2018 16:10:21 +0100 Subject: [PATCH 04/31] drm/virtio: virtio_gpu_cmd_resource_create_3d: drop unused fence arg Signed-off-by: Gerd Hoffmann Reviewed-by: Robert Foss Link: http://patchwork.freedesktop.org/patch/msgid/20181128151021.29565-3-kraxel@redhat.com --- drivers/gpu/drm/virtio/virtgpu_drv.h | 3 +-- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 2 +- drivers/gpu/drm/virtio/virtgpu_vq.c | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index d6cc1a92ca88..4e522e0b59e6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -324,8 +324,7 @@ void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, - struct virtio_gpu_resource_create_3d *rc_3d, - struct virtio_gpu_fence *fence); + struct virtio_gpu_resource_create_3d *rc_3d); void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq); void virtio_gpu_fence_ack(struct virtqueue *vq); diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index e9cdb4c7f654..161b80fee492 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -348,7 +348,7 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data, goto fail_backoff; } - virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL); + virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d); ret = virtio_gpu_object_attach(vgdev, qobj, fence); if (ret) { virtio_gpu_fence_cleanup(fence); diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 97038662b926..e27c4aedb809 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -820,8 +820,7 @@ void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, struct virtio_gpu_object *bo, - struct virtio_gpu_resource_create_3d *rc_3d, - struct virtio_gpu_fence *fence) + struct virtio_gpu_resource_create_3d *rc_3d) { struct virtio_gpu_resource_create_3d *cmd_p; struct virtio_gpu_vbuffer *vbuf; @@ -833,7 +832,7 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D); cmd_p->hdr.flags = 0; - virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); bo->created = true; } From 2f690fad237adea1bdce8ed9026cbf43cd9d8c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Wed, 28 Nov 2018 22:27:11 +0100 Subject: [PATCH 05/31] drm/rcar-du: Use drm_fbdev_generic_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CMA helper is already using the drm_fb_helper_generic_probe part of the generic fbdev emulation. This patch makes full use of the generic fbdev emulation by using its drm_client callbacks. This means that drm_mode_config_funcs->output_poll_changed and drm_driver->lastclose are now handled by the emulation code. Additionally fbdev unregister happens automatically on drm_dev_unregister(). The drm_fbdev_generic_setup() call is put after drm_dev_register() in the driver. This is done to highlight the fact that fbdev emulation is an internal client that makes use of the driver, it is not part of the driver as such. If fbdev setup fails, an error is printed, but the driver succeeds probing. drm_fbdev_generic_setup() handles mode_config.num_connector being zero. In that case it retries fbdev setup on the next .output_poll_changed. Cc: Laurent Pinchart Signed-off-by: Noralf Trønnes Acked-by: Sam Ravnborg Reviewed-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20181128212713.43500-4-noralf@tronnes.org --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 14 +++----------- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 -- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 21 --------------------- 3 files changed, 3 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 94f055186b95..f50a3b1864bb 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "rcar_du_drv.h" @@ -392,19 +393,11 @@ MODULE_DEVICE_TABLE(of, rcar_du_of_table); * DRM operations */ -static void rcar_du_lastclose(struct drm_device *dev) -{ - struct rcar_du_device *rcdu = dev->dev_private; - - drm_fbdev_cma_restore_mode(rcdu->fbdev); -} - DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops); static struct drm_driver rcar_du_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, - .lastclose = rcar_du_lastclose, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, @@ -460,9 +453,6 @@ static int rcar_du_remove(struct platform_device *pdev) drm_dev_unregister(ddev); - if (rcdu->fbdev) - drm_fbdev_cma_fini(rcdu->fbdev); - drm_kms_helper_poll_fini(ddev); drm_mode_config_cleanup(ddev); @@ -522,6 +512,8 @@ static int rcar_du_probe(struct platform_device *pdev) DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); + drm_fbdev_generic_setup(ddev, 32); + return 0; error: diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 9f5563296c5a..a68da79b424e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -20,7 +20,6 @@ struct clk; struct device; struct drm_device; -struct drm_fbdev_cma; struct rcar_du_device; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0) /* Per-CRTC IRQ and clock */ @@ -78,7 +77,6 @@ struct rcar_du_device { void __iomem *mmio; struct drm_device *ddev; - struct drm_fbdev_cma *fbdev; struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS]; unsigned int num_crtcs; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index fe6f65c94eef..9c7007d45408 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -255,13 +255,6 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, return drm_gem_fb_create(dev, file_priv, mode_cmd); } -static void rcar_du_output_poll_changed(struct drm_device *dev) -{ - struct rcar_du_device *rcdu = dev->dev_private; - - drm_fbdev_cma_hotplug_event(rcdu->fbdev); -} - /* ----------------------------------------------------------------------------- * Atomic Check and Update */ @@ -308,7 +301,6 @@ static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = { static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { .fb_create = rcar_du_fb_create, - .output_poll_changed = rcar_du_output_poll_changed, .atomic_check = rcar_du_atomic_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -543,7 +535,6 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) struct drm_device *dev = rcdu->ddev; struct drm_encoder *encoder; - struct drm_fbdev_cma *fbdev; unsigned int dpad0_sources; unsigned int num_encoders; unsigned int num_groups; @@ -682,17 +673,5 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) drm_kms_helper_poll_init(dev); - if (dev->mode_config.num_connector) { - fbdev = drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_connector); - if (IS_ERR(fbdev)) - return PTR_ERR(fbdev); - - rcdu->fbdev = fbdev; - } else { - dev_info(rcdu->dev, - "no connector found, disabling fbdev emulation\n"); - } - return 0; } From aa394b0dd68cb00c483e151dcd84713d4d517ed1 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 10:04:14 -0500 Subject: [PATCH 06/31] drm: Clear state->acquire_ctx before leaving drm_atomic_helper_commit_duplicated_state() drm_atomic_helper_commit_duplicated_state() sets state->acquire_ctx to the context given in the argument and leaves it in state after it quits. The lifetime of state and context are not guaranteed to be the same, so we shouldn't leave that pointer hanging around. This patch resets the context to NULL to avoid any oopses. Changes in v2: - Added to the set Suggested-by: Daniel Vetter Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181129150423.239081-1-sean@poorly.run --- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index bc9fc9665614..8bce94731cd6 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3229,7 +3229,7 @@ EXPORT_SYMBOL(drm_atomic_helper_suspend); int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx) { - int i; + int i, ret; struct drm_plane *plane; struct drm_plane_state *new_plane_state; struct drm_connector *connector; @@ -3248,7 +3248,11 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, for_each_new_connector_in_state(state, connector, new_conn_state, i) state->connectors[i].old_state = connector->state; - return drm_atomic_commit(state); + ret = drm_atomic_commit(state); + + state->acquire_ctx = NULL; + + return ret; } EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); From c232e9f41b136c141df9938024e521191a7b910d Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 10:04:15 -0500 Subject: [PATCH 07/31] drm: Move drm_mode_setcrtc() local re-init to failure path Instead of always re-initializing the variables we need to clean up on out, move the re-initialization into the branch that goes back to retry label. This is a lateral move right now, but will allow us to pull out the modeset locking into common code. I kept this change separate to make things easier to review. Changes in v2: - None Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181129150423.239081-2-sean@poorly.run --- drivers/gpu/drm/drm_crtc.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 268a182ae189..af4b94ce8e94 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -570,9 +570,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_mode_crtc *crtc_req = data; struct drm_crtc *crtc; struct drm_plane *plane; - struct drm_connector **connector_set, *connector; - struct drm_framebuffer *fb; - struct drm_display_mode *mode; + struct drm_connector **connector_set = NULL, *connector; + struct drm_framebuffer *fb = NULL; + struct drm_display_mode *mode = NULL; struct drm_mode_set set; uint32_t __user *set_connectors_ptr; struct drm_modeset_acquire_ctx ctx; @@ -601,10 +601,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, mutex_lock(&crtc->dev->mode_config.mutex); drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); retry: - connector_set = NULL; - fb = NULL; - mode = NULL; - ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); if (ret) goto out; @@ -766,6 +762,12 @@ out: } kfree(connector_set); drm_mode_destroy(dev, mode); + + /* In case we need to retry... */ + connector_set = NULL; + fb = NULL; + mode = NULL; + if (ret == -EDEADLK) { ret = drm_modeset_backoff(&ctx); if (!ret) From 2aa3eef85d4ac3843f4972269dbd39557e0ec0eb Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 10:04:16 -0500 Subject: [PATCH 08/31] drm: Move atomic_state_put after locks are dropped drm_atomic_state_put doesn't require any locking, and this makes things easier for switching to modeset_lock_all helpers in a future patch Changes in v2: - Moved state->acquire_ctx clear to a separate patch (Daniel) Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181129150423.239081-3-sean@poorly.run --- drivers/gpu/drm/drm_atomic_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8bce94731cd6..c7380ad3c51b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3294,9 +3294,9 @@ out: drm_modeset_backoff(&ctx); } - drm_atomic_state_put(state); drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + drm_atomic_state_put(state); return err; } From b7ea04d299c78b6cf96ab281a1683ff62a74f969 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 10:04:17 -0500 Subject: [PATCH 09/31] drm: Add DRM_MODESET_LOCK_BEGIN/END helpers This patch adds a couple of helpers to remove the boilerplate involved in grabbing all of the modeset locks. I've also converted the obvious cases in drm core to use the helpers. The only remaining instance of drm_modeset_lock_all_ctx() is in drm_framebuffer. It's complicated by the state clear that occurs on deadlock. ATM, there's no way to inject code in the deadlock path with the helpers, so it's unfit for conversion. Changes in v2: - Relocate ret argument to the end of the list (Daniel) - Incorporate Daniel's doc suggestions (Daniel) Suggested-by: Daniel Vetter Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181129150423.239081-4-sean@poorly.run --- drivers/gpu/drm/drm_atomic_helper.c | 51 +++++-------------------- drivers/gpu/drm/drm_color_mgmt.c | 14 +------ drivers/gpu/drm/drm_crtc.c | 15 ++------ drivers/gpu/drm/drm_modeset_lock.c | 6 +++ drivers/gpu/drm/drm_plane.c | 16 ++------ include/drm/drm_modeset_lock.h | 59 +++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c7380ad3c51b..0d58c40aa440 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3128,23 +3128,13 @@ void drm_atomic_helper_shutdown(struct drm_device *dev) struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_acquire_init(&ctx, 0); - while (1) { - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (!ret) - ret = __drm_atomic_helper_disable_all(dev, &ctx, true); - - if (ret != -EDEADLK) - break; - - drm_modeset_backoff(&ctx); - } + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + ret = __drm_atomic_helper_disable_all(dev, &ctx, true); if (ret) DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + DRM_MODESET_LOCK_ALL_END(ctx, ret); } EXPORT_SYMBOL(drm_atomic_helper_shutdown); @@ -3179,14 +3169,7 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) struct drm_atomic_state *state; int err; - drm_modeset_acquire_init(&ctx, 0); - -retry: - err = drm_modeset_lock_all_ctx(dev, &ctx); - if (err < 0) { - state = ERR_PTR(err); - goto unlock; - } + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); state = drm_atomic_helper_duplicate_state(dev, &ctx); if (IS_ERR(state)) @@ -3200,13 +3183,10 @@ retry: } unlock: - if (PTR_ERR(state) == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } + DRM_MODESET_LOCK_ALL_END(ctx, err); + if (err) + return ERR_PTR(err); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); return state; } EXPORT_SYMBOL(drm_atomic_helper_suspend); @@ -3280,22 +3260,11 @@ int drm_atomic_helper_resume(struct drm_device *dev, drm_mode_config_reset(dev); - drm_modeset_acquire_init(&ctx, 0); - while (1) { - err = drm_modeset_lock_all_ctx(dev, &ctx); - if (err) - goto out; + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); - err = drm_atomic_helper_commit_duplicated_state(state, &ctx); -out: - if (err != -EDEADLK) - break; + err = drm_atomic_helper_commit_duplicated_state(state, &ctx); - drm_modeset_backoff(&ctx); - } - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + DRM_MODESET_LOCK_ALL_END(ctx, err); drm_atomic_state_put(state); return err; diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 581cc3788223..07dcf47daafe 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -255,11 +255,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, if (crtc_lut->gamma_size != crtc->gamma_size) return -EINVAL; - drm_modeset_acquire_init(&ctx, 0); -retry: - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (ret) - goto out; + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; @@ -284,13 +280,7 @@ retry: crtc->gamma_size, &ctx); out: - if (ret == -EDEADLK) { - drm_modeset_backoff(&ctx); - goto retry; - } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - + DRM_MODESET_LOCK_ALL_END(ctx, ret); return ret; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index af4b94ce8e94..42cdb4181643 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -599,11 +599,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, plane = crtc->primary; mutex_lock(&crtc->dev->mode_config.mutex); - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); -retry: - ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); - if (ret) - goto out; + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ @@ -768,13 +765,7 @@ out: fb = NULL; mode = NULL; - if (ret == -EDEADLK) { - ret = drm_modeset_backoff(&ctx); - if (!ret) - goto retry; - } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + DRM_MODESET_LOCK_ALL_END(ctx, ret); mutex_unlock(&crtc->dev->mode_config.mutex); return ret; diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 8a5100685875..51f534db9107 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -56,6 +56,10 @@ * drm_modeset_drop_locks(ctx); * drm_modeset_acquire_fini(ctx); * + * For convenience this control flow is implemented in + * DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() for the case + * where all modeset locks need to be taken through drm_modeset_lock_all_ctx(). + * * If all that is needed is a single modeset lock, then the &struct * drm_modeset_acquire_ctx is not needed and the locking can be simplified * by passing a NULL instead of ctx in the drm_modeset_lock() call or @@ -383,6 +387,8 @@ EXPORT_SYMBOL(drm_modeset_unlock); * Locks acquired with this function should be released by calling the * drm_modeset_drop_locks() function on @ctx. * + * See also: DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() + * * Returns: 0 on success or a negative error-code on failure. */ int drm_modeset_lock_all_ctx(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 679455e36829..5f650d8fc66b 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -767,11 +767,8 @@ static int setplane_internal(struct drm_plane *plane, struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); -retry: - ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); - if (ret) - goto fail; + DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx, + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); if (drm_drv_uses_atomic_modeset(plane->dev)) ret = __setplane_atomic(plane, crtc, fb, @@ -782,14 +779,7 @@ retry: crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, &ctx); -fail: - if (ret == -EDEADLK) { - ret = drm_modeset_backoff(&ctx); - if (!ret) - goto retry; - } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + DRM_MODESET_LOCK_ALL_END(ctx, ret); return ret; } diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index a685d1bb21f2..a308f2d6496f 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -130,4 +130,63 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); int drm_modeset_lock_all_ctx(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +/** + * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks + * @dev: drm device + * @ctx: local modeset acquire context, will be dereferenced + * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init() + * @ret: local ret/err/etc variable to track error status + * + * Use these macros to simplify grabbing all modeset locks using a local + * context. This has the advantage of reducing boilerplate, but also properly + * checking return values where appropriate. + * + * Any code run between BEGIN and END will be holding the modeset locks. + * + * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and + * forth between the labels on deadlock and error conditions. + * + * Drivers can acquire additional modeset locks. If any lock acquisition + * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with + * the @ret parameter containing the return value of drm_modeset_lock(). + * + * Returns: + * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN() + * is 0, so no error checking is necessary + */ +#define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret) \ + drm_modeset_acquire_init(&ctx, flags); \ +modeset_lock_retry: \ + ret = drm_modeset_lock_all_ctx(dev, &ctx); \ + if (ret) \ + goto modeset_lock_fail; + +/** + * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks + * @ctx: local modeset acquire context, will be dereferenced + * @ret: local ret/err/etc variable to track error status + * + * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN + * if ret is -EDEADLK. + * + * It's important that you use the same ret variable for begin and end so + * deadlock conditions are properly handled. + * + * Returns: + * ret will be untouched unless it is -EDEADLK on entry. That means that if you + * successfully acquire the locks, ret will be whatever your code sets it to. If + * there is a deadlock or other failure with acquire or backoff, ret will be set + * to that failure. In both of these cases the code between BEGIN/END will not + * be run, so the failure will reflect the inability to grab the locks. + */ +#define DRM_MODESET_LOCK_ALL_END(ctx, ret) \ +modeset_lock_fail: \ + if (ret == -EDEADLK) { \ + ret = drm_modeset_backoff(&ctx); \ + if (!ret) \ + goto modeset_lock_retry; \ + } \ + drm_modeset_drop_locks(&ctx); \ + drm_modeset_acquire_fini(&ctx); + #endif /* DRM_MODESET_LOCK_H_ */ From 22be874012893d436438b538c21a896ed930fcc5 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 14:58:33 -0500 Subject: [PATCH 10/31] drm: TODO: Add DRM_MODESET_LOCK_ALL* conversion to todo.rst We should also get the drivers using the helpers. Seems like a good intermediate TODO item. Changes in v2: - Add line about replacing drm_modest_lock_all() (Daniel) Acked-by: Daniel Vetter Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20181129195838.222031-1-sean@poorly.run --- Documentation/gpu/todo.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index ab347dec5079..14191b64446d 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -241,6 +241,21 @@ struct drm_gem_object_funcs GEM objects can now have a function table instead of having the callbacks on the DRM driver struct. This is now the preferred way and drivers can be moved over. +Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate +--------------------------------------------------------- + +For cases where drivers are attempting to grab the modeset locks with a local +acquire context. Replace the boilerplate code surrounding +drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and +DRM_MODESET_LOCK_ALL_END() instead. + +This should also be done for all places where drm_modest_lock_all() is still +used. + +As a reference, take a look at the conversions already completed in drm core. + +Contact: Sean Paul, respective driver maintainers + Core refactorings ================= From b2e554d4df5e758306e81d64e1782f992a74b995 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:49 +0100 Subject: [PATCH 11/31] drm/vc4: Make vc4_lbm_size() return 0 when vertical scaling is disabled LBM is not needed when vertical scaling is disabled. Return 0 in this case to avoid allocating LBM memory that will anyway be unused. While at it, drop the test on ->is_unity which is now redundant. Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-1-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index c3ded0ba0441..f6e3e8d33115 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -395,10 +395,13 @@ static u32 vc4_lbm_size(struct drm_plane_state *state) u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); u32 lbm; + /* LBM is not needed when there's no vertical scaling. */ + if (vc4_state->y_scaling[0] == VC4_SCALING_NONE && + vc4_state->y_scaling[1] == VC4_SCALING_NONE) + return 0; + if (!vc4_state->is_yuv) { - if (vc4_state->is_unity) - return 0; - else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) + if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) lbm = pix_per_line * 8; else { /* In special cases, this multiplier might be 12. */ From 0a038c1c29a7a37724b39543ae36316745167239 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:50 +0100 Subject: [PATCH 12/31] drm/vc4: Move LBM creation out of vc4_plane_mode_set() We are about to use vc4_plane_mode_set() in the async check path, and async updates require that LBM size stay the same since they reuse the LBM from the previous state. So we definitely don't want to allocate a new LBM region that we know for sure will be free right away. Move the LBM allocation out of vc4_plane_mode_set() and call the new function (vc4_plane_update_lbm()) from vc4_plane_atomic_check(). Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-2-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_drv.h | 1 + drivers/gpu/drm/vc4/vc4_plane.c | 81 +++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index bd6ef1f31822..9ed05fb61eb6 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -338,6 +338,7 @@ struct vc4_plane_state { u32 pos0_offset; u32 pos2_offset; u32 ptr0_offset; + u32 lbm_offset; /* Offset where the plane's dlist was last stored in the * hardware at vc4_crtc_atomic_flush() time. diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index f6e3e8d33115..2db021f2d0ae 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -452,6 +452,43 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, } } +static int vc4_plane_allocate_lbm(struct drm_plane_state *state) +{ + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + unsigned long irqflags; + u32 lbm_size; + + lbm_size = vc4_lbm_size(state); + if (!lbm_size) + return 0; + + if (WARN_ON(!vc4_state->lbm_offset)) + return -EINVAL; + + /* Allocate the LBM memory that the HVS will use for temporary + * storage due to our scaling/format conversion. + */ + if (!vc4_state->lbm.allocated) { + int ret; + + spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, + &vc4_state->lbm, + lbm_size, 32, 0, 0); + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); + + if (ret) + return ret; + } else { + WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); + } + + vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; + + return 0; +} + /* Writes out a full display list for an active plane to the plane's * private dlist state. */ @@ -469,31 +506,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane, bool mix_plane_alpha; bool covers_screen; u32 scl0, scl1, pitch0; - u32 lbm_size, tiling; - unsigned long irqflags; + u32 tiling; u32 hvs_format = format->hvs; int ret, i; ret = vc4_plane_setup_clipping_and_scaling(state); - if (ret) - return ret; - - /* Allocate the LBM memory that the HVS will use for temporary - * storage due to our scaling/format conversion. - */ - lbm_size = vc4_lbm_size(state); - if (lbm_size) { - if (!vc4_state->lbm.allocated) { - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); - ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, - &vc4_state->lbm, - lbm_size, 32, 0, 0); - spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); - } else { - WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); - } - } - if (ret) return ret; @@ -717,15 +734,18 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); } + vc4_state->lbm_offset = 0; + if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || vc4_state->x_scaling[1] != VC4_SCALING_NONE || vc4_state->y_scaling[0] != VC4_SCALING_NONE || vc4_state->y_scaling[1] != VC4_SCALING_NONE) { - /* LBM Base Address. */ + /* Reserve a slot for the LBM Base Address. The real value will + * be set when calling vc4_plane_allocate_lbm(). + */ if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || - vc4_state->y_scaling[1] != VC4_SCALING_NONE) { - vc4_dlist_write(vc4_state, vc4_state->lbm.start); - } + vc4_state->y_scaling[1] != VC4_SCALING_NONE) + vc4_state->lbm_offset = vc4_state->dlist_count++; if (num_planes > 1) { /* Emit Cb/Cr as channel 0 and Y as channel @@ -785,13 +805,18 @@ static int vc4_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + int ret; vc4_state->dlist_count = 0; - if (plane_enabled(state)) - return vc4_plane_mode_set(plane, state); - else + if (!plane_enabled(state)) return 0; + + ret = vc4_plane_mode_set(plane, state); + if (ret) + return ret; + + return vc4_plane_allocate_lbm(state); } static void vc4_plane_atomic_update(struct drm_plane *plane, From 8d93844965c3d5a7bb57a80afd915463fa7a0824 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:51 +0100 Subject: [PATCH 13/31] drm/vc4: Don't check plane state more than once We are about to use vc4_plane_mode_set() in the async check path, but async check can decide that async update is not possible and force the driver to fallback to a sync update. All the checks that have been done on the plane state during async check stay valid, and checking it again is not necessary. Add a ->checked field to vc4_plane_state, and use it to track the status of the state (checked or not). Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-3-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_drv.h | 5 +++++ drivers/gpu/drm/vc4/vc4_plane.c | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 9ed05fb61eb6..4f87b03f837d 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -370,6 +370,11 @@ struct vc4_plane_state { * to enable background color fill. */ bool needs_bg_fill; + + /* Mark the dlist as initialized. Useful to avoid initializing it twice + * when async update is not possible. + */ + bool dlist_initialized; }; static inline struct vc4_plane_state * diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 2db021f2d0ae..a4faa5854a85 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -154,6 +154,7 @@ static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane return NULL; memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); + vc4_state->dlist_initialized = 0; __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); @@ -510,6 +511,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 hvs_format = format->hvs; int ret, i; + if (vc4_state->dlist_initialized) + return 0; + ret = vc4_plane_setup_clipping_and_scaling(state); if (ret) return ret; @@ -791,6 +795,13 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || state->alpha != DRM_BLEND_ALPHA_OPAQUE; + /* Flag the dlist as initialized to avoid checking it twice in case + * the async update check already called vc4_plane_mode_set() and + * decided to fallback to sync update because async update was not + * possible. + */ + vc4_state->dlist_initialized = 1; + return 0; } From 1d4118ca165e9cf393b29e606b7a3afddc76a3fb Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:52 +0100 Subject: [PATCH 14/31] drm/vc4: Rework the async update logic vc4_plane_atomic_async_check() was only based on the state->{crtc,src}_{w,h} which was fine since scaling was not allowed on the cursor plane. We are about to change that to properly support underscan, and, in order to make the async check more reliable, we call vc4_plane_mode_set() from there and check that only the pos0, pos2 and ptr0 entries in the dlist have changed. In vc4_plane_atomic_async_update(), we no longer call vc4_plane_atomic_check() since vc4_plane_mode_set() has already been called in vc4_plane_atomic_async_check(), and we don't need to allocate a new LBM region (we reuse the one from the current state). Note that we now have to manually update each field of the current plane state since it's no longer updated in place (not sure we have to sync all of them, but it's harmless if we do). We also drop the vc4_plane_async_set_fb() call (ptr0 dlist entry has been properly updated in vc4_plane_mode_set()) Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-4-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 87 +++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index a4faa5854a85..a2dea26320fb 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -895,30 +895,50 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, { struct vc4_plane_state *vc4_state, *new_vc4_state; - if (plane->state->fb != state->fb) { - vc4_plane_async_set_fb(plane, state->fb); - drm_atomic_set_fb_for_plane(plane->state, state->fb); - } - - /* Set the cursor's position on the screen. This is the - * expected change from the drm_mode_cursor_universal() - * helper. - */ + drm_atomic_set_fb_for_plane(plane->state, state->fb); plane->state->crtc_x = state->crtc_x; plane->state->crtc_y = state->crtc_y; - - /* Allow changing the start position within the cursor BO, if - * that matters. - */ + plane->state->crtc_w = state->crtc_w; + plane->state->crtc_h = state->crtc_h; plane->state->src_x = state->src_x; plane->state->src_y = state->src_y; - - /* Update the display list based on the new crtc_x/y. */ - vc4_plane_atomic_check(plane, state); + plane->state->src_w = state->src_w; + plane->state->src_h = state->src_h; + plane->state->src_h = state->src_h; + plane->state->alpha = state->alpha; + plane->state->pixel_blend_mode = state->pixel_blend_mode; + plane->state->rotation = state->rotation; + plane->state->zpos = state->zpos; + plane->state->normalized_zpos = state->normalized_zpos; + plane->state->color_encoding = state->color_encoding; + plane->state->color_range = state->color_range; + plane->state->src = state->src; + plane->state->dst = state->dst; + plane->state->visible = state->visible; new_vc4_state = to_vc4_plane_state(state); vc4_state = to_vc4_plane_state(plane->state); + vc4_state->crtc_x = new_vc4_state->crtc_x; + vc4_state->crtc_y = new_vc4_state->crtc_y; + vc4_state->crtc_h = new_vc4_state->crtc_h; + vc4_state->crtc_w = new_vc4_state->crtc_w; + vc4_state->src_x = new_vc4_state->src_x; + vc4_state->src_y = new_vc4_state->src_y; + memcpy(vc4_state->src_w, new_vc4_state->src_w, + sizeof(vc4_state->src_w)); + memcpy(vc4_state->src_h, new_vc4_state->src_h, + sizeof(vc4_state->src_h)); + memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling, + sizeof(vc4_state->x_scaling)); + memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling, + sizeof(vc4_state->y_scaling)); + vc4_state->is_unity = new_vc4_state->is_unity; + vc4_state->is_yuv = new_vc4_state->is_yuv; + memcpy(vc4_state->offsets, new_vc4_state->offsets, + sizeof(vc4_state->offsets)); + vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; + /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ vc4_state->dlist[vc4_state->pos0_offset] = new_vc4_state->dlist[vc4_state->pos0_offset]; @@ -942,13 +962,38 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane, static int vc4_plane_atomic_async_check(struct drm_plane *plane, struct drm_plane_state *state) { - /* No configuring new scaling in the fast path. */ - if (plane->state->crtc_w != state->crtc_w || - plane->state->crtc_h != state->crtc_h || - plane->state->src_w != state->src_w || - plane->state->src_h != state->src_h) + struct vc4_plane_state *old_vc4_state, *new_vc4_state; + int ret; + u32 i; + + ret = vc4_plane_mode_set(plane, state); + if (ret) + return ret; + + old_vc4_state = to_vc4_plane_state(plane->state); + new_vc4_state = to_vc4_plane_state(state); + if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || + old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || + old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || + old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || + vc4_lbm_size(plane->state) != vc4_lbm_size(state)) return -EINVAL; + /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update + * if anything else has changed, fallback to a sync update. + */ + for (i = 0; i < new_vc4_state->dlist_count; i++) { + if (i == new_vc4_state->pos0_offset || + i == new_vc4_state->pos2_offset || + i == new_vc4_state->ptr0_offset || + (new_vc4_state->lbm_offset && + i == new_vc4_state->lbm_offset)) + continue; + + if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i]) + return -EINVAL; + } + return 0; } From 5dc416d9c284e57d302be5fcf9bcb0f45aac28c2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:53 +0100 Subject: [PATCH 15/31] drm/vc4: Allow scaling on cursor plane Now that async update has been reworked to allow scaled planes to be updated asynchronously when the scaling params do not change, we can remove the NO_SCALING constraint on cursor planes. Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-5-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index a2dea26320fb..1b8a0a351c71 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -260,14 +260,12 @@ static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane) static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) { - struct drm_plane *plane = state->plane; struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); u32 subpixel_src_mask = (1 << 16) - 1; u32 format = fb->format->format; int num_planes = fb->format->num_planes; - int min_scale = 1, max_scale = INT_MAX; struct drm_crtc_state *crtc_state; u32 h_subsample, v_subsample; int i, ret; @@ -279,21 +277,8 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) return -EINVAL; } - /* No configuring scaling on the cursor plane, since it gets - * non-vblank-synced updates, and scaling requires LBM changes which - * have to be vblank-synced. - */ - if (plane->type == DRM_PLANE_TYPE_CURSOR) { - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; - } else { - min_scale = 1; - max_scale = INT_MAX; - } - - ret = drm_atomic_helper_check_plane_state(state, crtc_state, - min_scale, max_scale, - true, true); + ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1, + INT_MAX, true, true); if (ret) return ret; From 2c2853f7da33c72fa271edac520d36ae47097354 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 30 Nov 2018 10:02:54 +0100 Subject: [PATCH 16/31] drm/vc4: Allow YUV formats on cursor planes Now that scaling is allowed on cursor planes, we can also allow YUV formats. Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181130090254.594-6-boris.brezillon@bootlin.com --- drivers/gpu/drm/vc4/vc4_plane.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 1b8a0a351c71..75db62cbe468 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1095,7 +1095,6 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, struct drm_plane *plane = NULL; struct vc4_plane *vc4_plane; u32 formats[ARRAY_SIZE(hvs_formats)]; - u32 num_formats = 0; int ret = 0; unsigned i; static const uint64_t modifiers[] = { @@ -1112,20 +1111,13 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, if (!vc4_plane) return ERR_PTR(-ENOMEM); - for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { - /* Don't allow YUV in cursor planes, since that means - * tuning on the scaler, which we don't allow for the - * cursor. - */ - if (type != DRM_PLANE_TYPE_CURSOR || - hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { - formats[num_formats++] = hvs_formats[i].drm; - } - } + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) + formats[i] = hvs_formats[i].drm; + plane = &vc4_plane->base; ret = drm_universal_plane_init(dev, plane, 0, &vc4_plane_funcs, - formats, num_formats, + formats, ARRAY_SIZE(formats), modifiers, type, NULL); drm_plane_helper_add(plane, &vc4_plane_helper_funcs); From 615aa3d9aee28806f947cd1d99f1fd1f9b3e35b6 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 29 Nov 2018 15:36:48 -0500 Subject: [PATCH 17/31] drm: Fix compiler warning in drm_atomic_helper.c Kbuild was complaining about: >> drivers/gpu/drm/drm_atomic_helper.c:3169:27: warning: 'state' may be used uninitialized in this function [-Wmaybe-uninitialized] Now state can't actually be used uninitialized, but we'll assign a value anyways so it stops bellyaching. Kbuild config: link: https://lists.01.org/pipermail/kbuild-all/2018-November/055374.html tree: git://anongit.freedesktop.org/drm/drm-misc for-linux-next head: b7ea04d299c78b6cf96ab281a1683ff62a74f969 commit: b7ea04d299c78b6cf96ab281a1683ff62a74f969 [4/4] drm: Add DRM_MODESET_LOCK_BEGIN/END helpers config: x86_64-randconfig-x017-201847 (attached as .config) compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 reproduce: git checkout b7ea04d299c78b6cf96ab281a1683ff62a74f969 # save the attached .config to linux build tree make ARCH=x86_64 Fixes: b7ea04d299c7 ("drm: Add DRM_MODESET_LOCK_BEGIN/END helpers") Cc: Daniel Vetter Cc: Sean Paul Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Sean Paul Cc: David Airlie Cc: dri-devel@lists.freedesktop.org Reviewed-by: Daniel Vetter Signed-off-by: Sean Paul [seanpaul added extra details on airlied's suggestion] Link: https://patchwork.freedesktop.org/patch/msgid/20181129203652.223634-1-sean@poorly.run --- drivers/gpu/drm/drm_atomic_helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0d58c40aa440..0ee83efeb94a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3169,6 +3169,9 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) struct drm_atomic_state *state; int err; + /* This can never be returned, but it makes the compiler happy */ + state = ERR_PTR(-EINVAL); + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); state = drm_atomic_helper_duplicate_state(dev, &ctx); From 1d8224e790c7f9d0091a299b985c76ba0b229f43 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 28 Nov 2018 11:07:28 +0100 Subject: [PATCH 18/31] drm: Fix up drm_atomic_state_helper.[hc] extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've misplaced two functions by accident: - drm_atomic_helper_duplicate_state is really part of the resume/suspend/shutdown device-wide helpers. - drm_atomic_helper_legacy_gamma_set is part of the legacy ioctl compat helpers. Move them both back. Fixes: 9ef8a9dc4b21 ("drm: Extract drm_atomic_state_helper.[hc]") Cc: Ville Syrjälä Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20181128100728.4674-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 157 ++++++++++++++++++++++ drivers/gpu/drm/drm_atomic_state_helper.c | 157 ---------------------- include/drm/drm_atomic_helper.h | 7 + include/drm/drm_atomic_state_helper.h | 7 - 4 files changed, 164 insertions(+), 164 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0ee83efeb94a..8150fa8387d5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3138,6 +3138,93 @@ void drm_atomic_helper_shutdown(struct drm_device *dev) } EXPORT_SYMBOL(drm_atomic_helper_shutdown); +/** + * drm_atomic_helper_duplicate_state - duplicate an atomic state object + * @dev: DRM device + * @ctx: lock acquisition context + * + * Makes a copy of the current atomic state by looping over all objects and + * duplicating their respective states. This is used for example by suspend/ + * resume support code to save the state prior to suspend such that it can + * be restored upon resume. + * + * Note that this treats atomic state as persistent between save and restore. + * Drivers must make sure that this is possible and won't result in confusion + * or erroneous behaviour. + * + * Note that if callers haven't already acquired all modeset locks this might + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). + * + * Returns: + * A pointer to the copy of the atomic state object on success or an + * ERR_PTR()-encoded error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() + */ +struct drm_atomic_state * +drm_atomic_helper_duplicate_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + struct drm_plane *plane; + struct drm_crtc *crtc; + int err = 0; + + state = drm_atomic_state_alloc(dev); + if (!state) + return ERR_PTR(-ENOMEM); + + state->acquire_ctx = ctx; + + drm_for_each_crtc(crtc, dev) { + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + err = PTR_ERR(crtc_state); + goto free; + } + } + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + err = PTR_ERR(plane_state); + goto free; + } + } + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + struct drm_connector_state *conn_state; + + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + err = PTR_ERR(conn_state); + drm_connector_list_iter_end(&conn_iter); + goto free; + } + } + drm_connector_list_iter_end(&conn_iter); + + /* clear the acquire context so that it isn't accidentally reused */ + state->acquire_ctx = NULL; + +free: + if (err < 0) { + drm_atomic_state_put(state); + state = ERR_PTR(err); + } + + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); + /** * drm_atomic_helper_suspend - subsystem-level suspend helper * @dev: DRM device @@ -3407,3 +3494,73 @@ fail: return ret; } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); + +/** + * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table + * @crtc: CRTC object + * @red: red correction table + * @green: green correction table + * @blue: green correction table + * @size: size of the tables + * @ctx: lock acquire context + * + * Implements support for legacy gamma correction table for drivers + * that support color management through the DEGAMMA_LUT/GAMMA_LUT + * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for + * how the atomic color management and gamma tables work. + */ +int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + uint32_t size, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_device *dev = crtc->dev; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_property_blob *blob = NULL; + struct drm_color_lut *blob_data; + int i, ret = 0; + bool replaced; + + state = drm_atomic_state_alloc(crtc->dev); + if (!state) + return -ENOMEM; + + blob = drm_property_create_blob(dev, + sizeof(struct drm_color_lut) * size, + NULL); + if (IS_ERR(blob)) { + ret = PTR_ERR(blob); + blob = NULL; + goto fail; + } + + /* Prepare GAMMA_LUT with the legacy values. */ + blob_data = blob->data; + for (i = 0; i < size; i++) { + blob_data[i].red = red[i]; + blob_data[i].green = green[i]; + blob_data[i].blue = blue[i]; + } + + state->acquire_ctx = ctx; + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + /* Reset DEGAMMA_LUT and CTM properties. */ + replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); + replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); + replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); + crtc_state->color_mgmt_changed |= replaced; + + ret = drm_atomic_commit(state); + +fail: + drm_atomic_state_put(state); + drm_property_blob_put(blob); + return ret; +} +EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 3ba996069d69..60bd7d708e35 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -393,93 +393,6 @@ drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) } EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); -/** - * drm_atomic_helper_duplicate_state - duplicate an atomic state object - * @dev: DRM device - * @ctx: lock acquisition context - * - * Makes a copy of the current atomic state by looping over all objects and - * duplicating their respective states. This is used for example by suspend/ - * resume support code to save the state prior to suspend such that it can - * be restored upon resume. - * - * Note that this treats atomic state as persistent between save and restore. - * Drivers must make sure that this is possible and won't result in confusion - * or erroneous behaviour. - * - * Note that if callers haven't already acquired all modeset locks this might - * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). - * - * Returns: - * A pointer to the copy of the atomic state object on success or an - * ERR_PTR()-encoded error code on failure. - * - * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() - */ -struct drm_atomic_state * -drm_atomic_helper_duplicate_state(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_atomic_state *state; - struct drm_connector *conn; - struct drm_connector_list_iter conn_iter; - struct drm_plane *plane; - struct drm_crtc *crtc; - int err = 0; - - state = drm_atomic_state_alloc(dev); - if (!state) - return ERR_PTR(-ENOMEM); - - state->acquire_ctx = ctx; - - drm_for_each_crtc(crtc, dev) { - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - err = PTR_ERR(crtc_state); - goto free; - } - } - - drm_for_each_plane(plane, dev) { - struct drm_plane_state *plane_state; - - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - err = PTR_ERR(plane_state); - goto free; - } - } - - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(conn, &conn_iter) { - struct drm_connector_state *conn_state; - - conn_state = drm_atomic_get_connector_state(state, conn); - if (IS_ERR(conn_state)) { - err = PTR_ERR(conn_state); - drm_connector_list_iter_end(&conn_iter); - goto free; - } - } - drm_connector_list_iter_end(&conn_iter); - - /* clear the acquire context so that it isn't accidentally reused */ - state->acquire_ctx = NULL; - -free: - if (err < 0) { - drm_atomic_state_put(state); - state = ERR_PTR(err); - } - - return state; -} -EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); - /** * __drm_atomic_helper_connector_destroy_state - release connector state * @state: connector state object to release @@ -515,76 +428,6 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, } EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); -/** - * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table - * @crtc: CRTC object - * @red: red correction table - * @green: green correction table - * @blue: green correction table - * @size: size of the tables - * @ctx: lock acquire context - * - * Implements support for legacy gamma correction table for drivers - * that support color management through the DEGAMMA_LUT/GAMMA_LUT - * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for - * how the atomic color management and gamma tables work. - */ -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx) -{ - struct drm_device *dev = crtc->dev; - struct drm_atomic_state *state; - struct drm_crtc_state *crtc_state; - struct drm_property_blob *blob = NULL; - struct drm_color_lut *blob_data; - int i, ret = 0; - bool replaced; - - state = drm_atomic_state_alloc(crtc->dev); - if (!state) - return -ENOMEM; - - blob = drm_property_create_blob(dev, - sizeof(struct drm_color_lut) * size, - NULL); - if (IS_ERR(blob)) { - ret = PTR_ERR(blob); - blob = NULL; - goto fail; - } - - /* Prepare GAMMA_LUT with the legacy values. */ - blob_data = blob->data; - for (i = 0; i < size; i++) { - blob_data[i].red = red[i]; - blob_data[i].green = green[i]; - blob_data[i].blue = blue[i]; - } - - state->acquire_ctx = ctx; - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto fail; - } - - /* Reset DEGAMMA_LUT and CTM properties. */ - replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); - replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); - replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); - crtc_state->color_mgmt_changed |= replaced; - - ret = drm_atomic_commit(state); - -fail: - drm_atomic_state_put(state); - drm_property_blob_put(blob); - return ret; -} -EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); - /** * __drm_atomic_helper_private_duplicate_state - copy atomic private state * @obj: CRTC object diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 25ca0097563e..58214be3bf3d 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -127,6 +127,9 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); void drm_atomic_helper_shutdown(struct drm_device *dev); +struct drm_atomic_state * +drm_atomic_helper_duplicate_state(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); @@ -145,6 +148,10 @@ int drm_atomic_helper_page_flip_target( uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx); +int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, + u16 *red, u16 *green, u16 *blue, + uint32_t size, + struct drm_modeset_acquire_ctx *ctx); /** * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h index 5b82ccfdb502..66c92cbd8e16 100644 --- a/include/drm/drm_atomic_state_helper.h +++ b/include/drm/drm_atomic_state_helper.h @@ -65,16 +65,9 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector, struct drm_connector_state *state); struct drm_connector_state * drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); -struct drm_atomic_state * -drm_atomic_helper_duplicate_state(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx); void __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, struct drm_connector_state *state); -int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, - uint32_t size, - struct drm_modeset_acquire_ctx *ctx); void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, struct drm_private_state *state); From 1584f16ca96ef124aad79efa3303cff5f3530e2c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 28 Nov 2018 15:09:25 -0800 Subject: [PATCH 19/31] drm/v3d: Add support for submitting jobs to the TFU. The TFU can copy from raster, UIF, and SAND input images to UIF output images, with optional mipmap generation. This will certainly be useful for media EGL image input, but is also useful immediately for mipmap generation without bogging the V3D core down. For now we only run the queue 1 job deep, and don't have any hang recovery (though I don't think we should need it, with TFU). Queuing multiple jobs in the HW will require synchronizing the YUV coefficient regs updates since they don't get FIFOed with the job. v2: Change the ioctl to IOW instead of IOWR, always set COEF0, explain why TFU is AUTH, clarify the syncing docs, drop the unused TFU interrupt regs (you're expected to use the hub's), don't take &bo->base for NULL bos. v3: Fix a little whitespace alignment (noticed by checkpatch), rebase on drm_sched_job_cleanup() changes. Signed-off-by: Eric Anholt Reviewed-by: Dave Emett (v2) Link: https://patchwork.freedesktop.org/patch/264607/ --- drivers/gpu/drm/v3d/v3d_drv.c | 15 ++- drivers/gpu/drm/v3d/v3d_drv.h | 32 +++++- drivers/gpu/drm/v3d/v3d_gem.c | 178 ++++++++++++++++++++++++++++---- drivers/gpu/drm/v3d/v3d_irq.c | 12 ++- drivers/gpu/drm/v3d/v3d_regs.h | 49 +++++++++ drivers/gpu/drm/v3d/v3d_sched.c | 147 ++++++++++++++++++++++---- drivers/gpu/drm/v3d/v3d_trace.h | 20 ++++ include/uapi/drm/v3d_drm.h | 25 +++++ 8 files changed, 427 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 2a85fa68ffea..f0afcec72c34 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -112,10 +112,15 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, return 0; } - /* Any params that aren't just register reads would go here. */ - DRM_DEBUG("Unknown parameter %d\n", args->param); - return -EINVAL; + switch (args->param) { + case DRM_V3D_PARAM_SUPPORTS_TFU: + args->value = 1; + return 0; + default: + DRM_DEBUG("Unknown parameter %d\n", args->param); + return -EINVAL; + } } static int @@ -170,7 +175,8 @@ static const struct file_operations v3d_drm_fops = { /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP * protection between clients. Note that render nodes would be be * able to submit CLs that could access BOs from clients authenticated - * with the master node. + * with the master node. The TFU doesn't use the GMP, so it would + * need to stay DRM_AUTH until we do buffer size/offset validation. */ static const struct drm_ioctl_desc v3d_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), @@ -179,6 +185,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), }; static const struct vm_operations_struct v3d_vm_ops = { diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index cbe5be0c47eb..dcb772a19191 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -7,19 +7,18 @@ #include #include #include +#include "uapi/drm/v3d_drm.h" #define GMP_GRANULARITY (128 * 1024) -/* Enum for each of the V3D queues. We maintain various queue - * tracking as an array because at some point we'll want to support - * the TFU (texture formatting unit) as another queue. - */ +/* Enum for each of the V3D queues. */ enum v3d_queue { V3D_BIN, V3D_RENDER, + V3D_TFU, }; -#define V3D_MAX_QUEUES (V3D_RENDER + 1) +#define V3D_MAX_QUEUES (V3D_TFU + 1) struct v3d_queue_state { struct drm_gpu_scheduler sched; @@ -68,6 +67,7 @@ struct v3d_dev { struct v3d_exec_info *bin_job; struct v3d_exec_info *render_job; + struct v3d_tfu_job *tfu_job; struct v3d_queue_state queue[V3D_MAX_QUEUES]; @@ -218,6 +218,25 @@ struct v3d_exec_info { u32 qma, qms, qts; }; +struct v3d_tfu_job { + struct drm_sched_job base; + + struct drm_v3d_submit_tfu args; + + /* An optional fence userspace can pass in for the job to depend on. */ + struct dma_fence *in_fence; + + /* v3d fence to be signaled by IRQ handler when the job is complete. */ + struct dma_fence *done_fence; + + struct v3d_dev *v3d; + + struct kref refcount; + + /* This is the array of BOs that were looked up at the start of exec. */ + struct v3d_bo *bo[4]; +}; + /** * _wait_for - magic (register) wait macro * @@ -281,9 +300,12 @@ int v3d_gem_init(struct drm_device *dev); void v3d_gem_destroy(struct drm_device *dev); int v3d_submit_cl_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void v3d_exec_put(struct v3d_exec_info *exec); +void v3d_tfu_job_put(struct v3d_tfu_job *exec); void v3d_reset(struct v3d_dev *v3d); void v3d_invalidate_caches(struct v3d_dev *v3d); void v3d_flush_caches(struct v3d_dev *v3d); diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 1e8947c7d954..6abe2fa43306 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -207,26 +207,27 @@ v3d_flush_caches(struct v3d_dev *v3d) } static void -v3d_attach_object_fences(struct v3d_exec_info *exec) +v3d_attach_object_fences(struct v3d_bo **bos, int bo_count, + struct dma_fence *fence) { - struct dma_fence *out_fence = exec->render_done_fence; int i; - for (i = 0; i < exec->bo_count; i++) { + for (i = 0; i < bo_count; i++) { /* XXX: Use shared fences for read-only objects. */ - reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence); + reservation_object_add_excl_fence(bos[i]->resv, fence); } } static void v3d_unlock_bo_reservations(struct drm_device *dev, - struct v3d_exec_info *exec, + struct v3d_bo **bos, + int bo_count, struct ww_acquire_ctx *acquire_ctx) { int i; - for (i = 0; i < exec->bo_count; i++) - ww_mutex_unlock(&exec->bo[i]->resv->lock); + for (i = 0; i < bo_count; i++) + ww_mutex_unlock(&bos[i]->resv->lock); ww_acquire_fini(acquire_ctx); } @@ -240,7 +241,8 @@ v3d_unlock_bo_reservations(struct drm_device *dev, */ static int v3d_lock_bo_reservations(struct drm_device *dev, - struct v3d_exec_info *exec, + struct v3d_bo **bos, + int bo_count, struct ww_acquire_ctx *acquire_ctx) { int contended_lock = -1; @@ -250,7 +252,7 @@ v3d_lock_bo_reservations(struct drm_device *dev, retry: if (contended_lock != -1) { - struct v3d_bo *bo = exec->bo[contended_lock]; + struct v3d_bo *bo = bos[contended_lock]; ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, acquire_ctx); @@ -260,20 +262,20 @@ retry: } } - for (i = 0; i < exec->bo_count; i++) { + for (i = 0; i < bo_count; i++) { if (i == contended_lock) continue; - ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock, + ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock, acquire_ctx); if (ret) { int j; for (j = 0; j < i; j++) - ww_mutex_unlock(&exec->bo[j]->resv->lock); + ww_mutex_unlock(&bos[j]->resv->lock); if (contended_lock != -1 && contended_lock >= i) { - struct v3d_bo *bo = exec->bo[contended_lock]; + struct v3d_bo *bo = bos[contended_lock]; ww_mutex_unlock(&bo->resv->lock); } @@ -293,10 +295,11 @@ retry: /* Reserve space for our shared (read-only) fence references, * before we commit the CL to the hardware. */ - for (i = 0; i < exec->bo_count; i++) { - ret = reservation_object_reserve_shared(exec->bo[i]->resv, 1); + for (i = 0; i < bo_count; i++) { + ret = reservation_object_reserve_shared(bos[i]->resv, 1); if (ret) { - v3d_unlock_bo_reservations(dev, exec, acquire_ctx); + v3d_unlock_bo_reservations(dev, bos, bo_count, + acquire_ctx); return ret; } } @@ -419,6 +422,33 @@ void v3d_exec_put(struct v3d_exec_info *exec) kref_put(&exec->refcount, v3d_exec_cleanup); } +static void +v3d_tfu_job_cleanup(struct kref *ref) +{ + struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job, + refcount); + struct v3d_dev *v3d = job->v3d; + unsigned int i; + + dma_fence_put(job->in_fence); + dma_fence_put(job->done_fence); + + for (i = 0; i < ARRAY_SIZE(job->bo); i++) { + if (job->bo[i]) + drm_gem_object_put_unlocked(&job->bo[i]->base); + } + + pm_runtime_mark_last_busy(v3d->dev); + pm_runtime_put_autosuspend(v3d->dev); + + kfree(job); +} + +void v3d_tfu_job_put(struct v3d_tfu_job *job) +{ + kref_put(&job->refcount, v3d_tfu_job_cleanup); +} + int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -536,7 +566,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, if (ret) goto fail; - ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx); + ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count, + &acquire_ctx); if (ret) goto fail; @@ -570,9 +601,10 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, &v3d_priv->sched_entity[V3D_RENDER]); mutex_unlock(&v3d->sched_lock); - v3d_attach_object_fences(exec); + v3d_attach_object_fences(exec->bo, exec->bo_count, + exec->render_done_fence); - v3d_unlock_bo_reservations(dev, exec, &acquire_ctx); + v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx); /* Update the return sync object for the */ sync_out = drm_syncobj_find(file_priv, args->out_sync); @@ -588,13 +620,119 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, fail_unreserve: mutex_unlock(&v3d->sched_lock); - v3d_unlock_bo_reservations(dev, exec, &acquire_ctx); + v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx); fail: v3d_exec_put(exec); return ret; } +/** + * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D. + * @dev: DRM device + * @data: ioctl argument + * @file_priv: DRM file for this fd + * + * Userspace provides the register setup for the TFU, which we don't + * need to validate since the TFU is behind the MMU. + */ +int +v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct v3d_dev *v3d = to_v3d_dev(dev); + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; + struct drm_v3d_submit_tfu *args = data; + struct v3d_tfu_job *job; + struct ww_acquire_ctx acquire_ctx; + struct drm_syncobj *sync_out; + struct dma_fence *sched_done_fence; + int ret = 0; + int bo_count; + + job = kcalloc(1, sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + ret = pm_runtime_get_sync(v3d->dev); + if (ret < 0) { + kfree(job); + return ret; + } + + kref_init(&job->refcount); + + ret = drm_syncobj_find_fence(file_priv, args->in_sync, + 0, 0, &job->in_fence); + if (ret == -EINVAL) + goto fail; + + job->args = *args; + job->v3d = v3d; + + spin_lock(&file_priv->table_lock); + for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) { + struct drm_gem_object *bo; + + if (!args->bo_handles[bo_count]) + break; + + bo = idr_find(&file_priv->object_idr, + args->bo_handles[bo_count]); + if (!bo) { + DRM_DEBUG("Failed to look up GEM BO %d: %d\n", + bo_count, args->bo_handles[bo_count]); + ret = -ENOENT; + spin_unlock(&file_priv->table_lock); + goto fail; + } + drm_gem_object_get(bo); + job->bo[bo_count] = to_v3d_bo(bo); + } + spin_unlock(&file_priv->table_lock); + + ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); + if (ret) + goto fail; + + mutex_lock(&v3d->sched_lock); + ret = drm_sched_job_init(&job->base, + &v3d_priv->sched_entity[V3D_TFU], + v3d_priv); + if (ret) + goto fail_unreserve; + + sched_done_fence = dma_fence_get(&job->base.s_fence->finished); + + kref_get(&job->refcount); /* put by scheduler job completion */ + drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]); + mutex_unlock(&v3d->sched_lock); + + v3d_attach_object_fences(job->bo, bo_count, sched_done_fence); + + v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); + + /* Update the return sync object */ + sync_out = drm_syncobj_find(file_priv, args->out_sync); + if (sync_out) { + drm_syncobj_replace_fence(sync_out, 0, sched_done_fence); + drm_syncobj_put(sync_out); + } + dma_fence_put(sched_done_fence); + + v3d_tfu_job_put(job); + + return 0; + +fail_unreserve: + mutex_unlock(&v3d->sched_lock); + v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); +fail: + v3d_tfu_job_put(job); + + return ret; +} + int v3d_gem_init(struct drm_device *dev) { diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index e07514eb11b5..dd7a7b0bd5a1 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -4,8 +4,8 @@ /** * DOC: Interrupt management for the V3D engine * - * When we take a binning or rendering flush done interrupt, we need - * to signal the fence for that job so that the scheduler can queue up + * When we take a bin, render, or TFU done interrupt, we need to + * signal the fence for that job so that the scheduler can queue up * the next one and unblock any waiters. * * When we take the binner out of memory interrupt, we need to @@ -23,7 +23,8 @@ #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ V3D_HUB_INT_MMU_PTI | \ - V3D_HUB_INT_MMU_CAP)) + V3D_HUB_INT_MMU_CAP | \ + V3D_HUB_INT_TFUC)) static void v3d_overflow_mem_work(struct work_struct *work) @@ -117,6 +118,11 @@ v3d_hub_irq(int irq, void *arg) /* Acknowledge the interrupts we're handling here. */ V3D_WRITE(V3D_HUB_INT_CLR, intsts); + if (intsts & V3D_HUB_INT_TFUC) { + dma_fence_signal(v3d->tfu_job->done_fence); + status = IRQ_HANDLED; + } + if (intsts & (V3D_HUB_INT_MMU_WRV | V3D_HUB_INT_MMU_PTI | V3D_HUB_INT_MMU_CAP)) { diff --git a/drivers/gpu/drm/v3d/v3d_regs.h b/drivers/gpu/drm/v3d/v3d_regs.h index c3a5e4e44f73..6ccdee9d47bd 100644 --- a/drivers/gpu/drm/v3d/v3d_regs.h +++ b/drivers/gpu/drm/v3d/v3d_regs.h @@ -86,6 +86,55 @@ # define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0) +#define V3D_TFU_CS 0x00400 +/* Stops current job, empties input fifo. */ +# define V3D_TFU_CS_TFURST BIT(31) +# define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16) +# define V3D_TFU_CS_CVTCT_SHIFT 16 +# define V3D_TFU_CS_NFREE_MASK V3D_MASK(13, 8) +# define V3D_TFU_CS_NFREE_SHIFT 8 +# define V3D_TFU_CS_BUSY BIT(0) + +#define V3D_TFU_SU 0x00404 +/* Interrupt when FINTTHR input slots are free (0 = disabled) */ +# define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8) +# define V3D_TFU_SU_FINTTHR_SHIFT 8 +/* Skips resetting the CRC at the start of CRC generation. */ +# define V3D_TFU_SU_CRCCHAIN BIT(4) +/* skips writes, computes CRC of the image. miplevels must be 0. */ +# define V3D_TFU_SU_CRC BIT(3) +# define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0) +# define V3D_TFU_SU_THROTTLE_SHIFT 0 + +#define V3D_TFU_ICFG 0x00408 +/* Interrupt when the conversion is complete. */ +# define V3D_TFU_ICFG_IOC BIT(0) + +/* Input Image Address */ +#define V3D_TFU_IIA 0x0040c +/* Input Chroma Address */ +#define V3D_TFU_ICA 0x00410 +/* Input Image Stride */ +#define V3D_TFU_IIS 0x00414 +/* Input Image U-Plane Address */ +#define V3D_TFU_IUA 0x00418 +/* Output Image Address */ +#define V3D_TFU_IOA 0x0041c +/* Image Output Size */ +#define V3D_TFU_IOS 0x00420 +/* TFU YUV Coefficient 0 */ +#define V3D_TFU_COEF0 0x00424 +/* Use these regs instead of the defaults. */ +# define V3D_TFU_COEF0_USECOEF BIT(31) +/* TFU YUV Coefficient 1 */ +#define V3D_TFU_COEF1 0x00428 +/* TFU YUV Coefficient 2 */ +#define V3D_TFU_COEF2 0x0042c +/* TFU YUV Coefficient 3 */ +#define V3D_TFU_COEF3 0x00430 + +#define V3D_TFU_CRC 0x00434 + /* Per-MMU registers. */ #define V3D_MMUC_CONTROL 0x01000 diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index c66d0ce21435..f7508e907536 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -30,6 +30,12 @@ to_v3d_job(struct drm_sched_job *sched_job) return container_of(sched_job, struct v3d_job, base); } +static struct v3d_tfu_job * +to_tfu_job(struct drm_sched_job *sched_job) +{ + return container_of(sched_job, struct v3d_tfu_job, base); +} + static void v3d_job_free(struct drm_sched_job *sched_job) { @@ -40,6 +46,16 @@ v3d_job_free(struct drm_sched_job *sched_job) v3d_exec_put(job->exec); } +static void +v3d_tfu_job_free(struct drm_sched_job *sched_job) +{ + struct v3d_tfu_job *job = to_tfu_job(sched_job); + + drm_sched_job_cleanup(sched_job); + + v3d_tfu_job_put(job); +} + /** * Returns the fences that the bin or render job depends on, one by one. * v3d_job_run() won't be called until all of them have been signaled. @@ -78,6 +94,27 @@ v3d_job_dependency(struct drm_sched_job *sched_job, return fence; } +/** + * Returns the fences that the TFU job depends on, one by one. + * v3d_tfu_job_run() won't be called until all of them have been + * signaled. + */ +static struct dma_fence * +v3d_tfu_job_dependency(struct drm_sched_job *sched_job, + struct drm_sched_entity *s_entity) +{ + struct v3d_tfu_job *job = to_tfu_job(sched_job); + struct dma_fence *fence; + + fence = job->in_fence; + if (fence) { + job->in_fence = NULL; + return fence; + } + + return NULL; +} + static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job) { struct v3d_job *job = to_v3d_job(sched_job); @@ -149,28 +186,47 @@ static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job) return fence; } -static void -v3d_job_timedout(struct drm_sched_job *sched_job) +static struct dma_fence * +v3d_tfu_job_run(struct drm_sched_job *sched_job) { - struct v3d_job *job = to_v3d_job(sched_job); - struct v3d_exec_info *exec = job->exec; - struct v3d_dev *v3d = exec->v3d; - enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; - enum v3d_queue q; - u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); - u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); + struct v3d_tfu_job *job = to_tfu_job(sched_job); + struct v3d_dev *v3d = job->v3d; + struct drm_device *dev = &v3d->drm; + struct dma_fence *fence; - /* If the current address or return address have changed, then - * the GPU has probably made progress and we should delay the - * reset. This could fail if the GPU got in an infinite loop - * in the CL, but that is pretty unlikely outside of an i-g-t - * testcase. - */ - if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { - job->timedout_ctca = ctca; - job->timedout_ctra = ctra; - return; + fence = v3d_fence_create(v3d, V3D_TFU); + if (IS_ERR(fence)) + return NULL; + + v3d->tfu_job = job; + if (job->done_fence) + dma_fence_put(job->done_fence); + job->done_fence = dma_fence_get(fence); + + trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); + + V3D_WRITE(V3D_TFU_IIA, job->args.iia); + V3D_WRITE(V3D_TFU_IIS, job->args.iis); + V3D_WRITE(V3D_TFU_ICA, job->args.ica); + V3D_WRITE(V3D_TFU_IUA, job->args.iua); + V3D_WRITE(V3D_TFU_IOA, job->args.ioa); + V3D_WRITE(V3D_TFU_IOS, job->args.ios); + V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]); + if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) { + V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]); + V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]); + V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]); } + /* ICFG kicks off the job. */ + V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC); + + return fence; +} + +static void +v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) +{ + enum v3d_queue q; mutex_lock(&v3d->reset_lock); @@ -195,6 +251,39 @@ v3d_job_timedout(struct drm_sched_job *sched_job) mutex_unlock(&v3d->reset_lock); } +static void +v3d_job_timedout(struct drm_sched_job *sched_job) +{ + struct v3d_job *job = to_v3d_job(sched_job); + struct v3d_exec_info *exec = job->exec; + struct v3d_dev *v3d = exec->v3d; + enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; + u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); + u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); + + /* If the current address or return address have changed, then + * the GPU has probably made progress and we should delay the + * reset. This could fail if the GPU got in an infinite loop + * in the CL, but that is pretty unlikely outside of an i-g-t + * testcase. + */ + if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { + job->timedout_ctca = ctca; + job->timedout_ctra = ctra; + return; + } + + v3d_gpu_reset_for_timeout(v3d, sched_job); +} + +static void +v3d_tfu_job_timedout(struct drm_sched_job *sched_job) +{ + struct v3d_tfu_job *job = to_tfu_job(sched_job); + + v3d_gpu_reset_for_timeout(job->v3d, sched_job); +} + static const struct drm_sched_backend_ops v3d_sched_ops = { .dependency = v3d_job_dependency, .run_job = v3d_job_run, @@ -202,6 +291,13 @@ static const struct drm_sched_backend_ops v3d_sched_ops = { .free_job = v3d_job_free }; +static const struct drm_sched_backend_ops v3d_tfu_sched_ops = { + .dependency = v3d_tfu_job_dependency, + .run_job = v3d_tfu_job_run, + .timedout_job = v3d_tfu_job_timedout, + .free_job = v3d_tfu_job_free +}; + int v3d_sched_init(struct v3d_dev *v3d) { @@ -232,6 +328,19 @@ v3d_sched_init(struct v3d_dev *v3d) return ret; } + ret = drm_sched_init(&v3d->queue[V3D_TFU].sched, + &v3d_tfu_sched_ops, + hw_jobs_limit, job_hang_limit, + msecs_to_jiffies(hang_limit_ms), + "v3d_tfu"); + if (ret) { + dev_err(v3d->dev, "Failed to create TFU scheduler: %d.", + ret); + drm_sched_fini(&v3d->queue[V3D_RENDER].sched); + drm_sched_fini(&v3d->queue[V3D_BIN].sched); + return ret; + } + return 0; } diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h index 85dd351e1e09..f54ed9cd3444 100644 --- a/drivers/gpu/drm/v3d/v3d_trace.h +++ b/drivers/gpu/drm/v3d/v3d_trace.h @@ -42,6 +42,26 @@ TRACE_EVENT(v3d_submit_cl, __entry->ctnqea) ); +TRACE_EVENT(v3d_submit_tfu, + TP_PROTO(struct drm_device *dev, + uint64_t seqno), + TP_ARGS(dev, seqno), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u64, seqno) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->seqno = seqno; + ), + + TP_printk("dev=%u, seqno=%llu", + __entry->dev, + __entry->seqno) +); + TRACE_EVENT(v3d_reset_begin, TP_PROTO(struct drm_device *dev), TP_ARGS(dev), diff --git a/include/uapi/drm/v3d_drm.h b/include/uapi/drm/v3d_drm.h index b1e5de076b0f..35c7d813c66e 100644 --- a/include/uapi/drm/v3d_drm.h +++ b/include/uapi/drm/v3d_drm.h @@ -36,6 +36,7 @@ extern "C" { #define DRM_V3D_MMAP_BO 0x03 #define DRM_V3D_GET_PARAM 0x04 #define DRM_V3D_GET_BO_OFFSET 0x05 +#define DRM_V3D_SUBMIT_TFU 0x06 #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) @@ -43,6 +44,7 @@ extern "C" { #define DRM_IOCTL_V3D_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo) #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param) #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset) +#define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) /** * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D @@ -179,6 +181,7 @@ enum drm_v3d_param { DRM_V3D_PARAM_V3D_CORE0_IDENT0, DRM_V3D_PARAM_V3D_CORE0_IDENT1, DRM_V3D_PARAM_V3D_CORE0_IDENT2, + DRM_V3D_PARAM_SUPPORTS_TFU, }; struct drm_v3d_get_param { @@ -197,6 +200,28 @@ struct drm_v3d_get_bo_offset { __u32 offset; }; +struct drm_v3d_submit_tfu { + __u32 icfg; + __u32 iia; + __u32 iis; + __u32 ica; + __u32 iua; + __u32 ioa; + __u32 ios; + __u32 coef[4]; + /* First handle is the output BO, following are other inputs. + * 0 for unused. + */ + __u32 bo_handles[4]; + /* sync object to block on before running the TFU job. Each TFU + * job will execute in the order submitted to its FD. Synchronization + * against rendering jobs requires using sync objects. + */ + __u32 in_sync; + /* Sync object to signal when the TFU job is done. */ + __u32 out_sync; +}; + #if defined(__cplusplus) } #endif From e14a07fc4b961a75f6c275d6bd670ba54fbdae14 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 28 Nov 2018 15:09:26 -0800 Subject: [PATCH 20/31] drm/v3d: Drop the "dev" argument to lock/unlock of BO reservations. They were unused, as Dave Emett noticed in TFU review. Signed-off-by: Eric Anholt Cc: Dave Emett Link: https://patchwork.freedesktop.org/patch/msgid/20181128230927.10951-2-eric@anholt.net Reviewed-by: Daniel Vetter --- drivers/gpu/drm/v3d/v3d_gem.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 6abe2fa43306..8b4af512450f 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -219,8 +219,7 @@ v3d_attach_object_fences(struct v3d_bo **bos, int bo_count, } static void -v3d_unlock_bo_reservations(struct drm_device *dev, - struct v3d_bo **bos, +v3d_unlock_bo_reservations(struct v3d_bo **bos, int bo_count, struct ww_acquire_ctx *acquire_ctx) { @@ -240,8 +239,7 @@ v3d_unlock_bo_reservations(struct drm_device *dev, * to v3d, so we don't attach dma-buf fences to them. */ static int -v3d_lock_bo_reservations(struct drm_device *dev, - struct v3d_bo **bos, +v3d_lock_bo_reservations(struct v3d_bo **bos, int bo_count, struct ww_acquire_ctx *acquire_ctx) { @@ -298,7 +296,7 @@ retry: for (i = 0; i < bo_count; i++) { ret = reservation_object_reserve_shared(bos[i]->resv, 1); if (ret) { - v3d_unlock_bo_reservations(dev, bos, bo_count, + v3d_unlock_bo_reservations(bos, bo_count, acquire_ctx); return ret; } @@ -566,7 +564,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, if (ret) goto fail; - ret = v3d_lock_bo_reservations(dev, exec->bo, exec->bo_count, + ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); if (ret) goto fail; @@ -604,7 +602,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, v3d_attach_object_fences(exec->bo, exec->bo_count, exec->render_done_fence); - v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx); + v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); /* Update the return sync object for the */ sync_out = drm_syncobj_find(file_priv, args->out_sync); @@ -620,7 +618,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, fail_unreserve: mutex_unlock(&v3d->sched_lock); - v3d_unlock_bo_reservations(dev, exec->bo, exec->bo_count, &acquire_ctx); + v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); fail: v3d_exec_put(exec); @@ -691,7 +689,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, } spin_unlock(&file_priv->table_lock); - ret = v3d_lock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); + ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx); if (ret) goto fail; @@ -710,7 +708,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, v3d_attach_object_fences(job->bo, bo_count, sched_done_fence); - v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); + v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); /* Update the return sync object */ sync_out = drm_syncobj_find(file_priv, args->out_sync); @@ -726,7 +724,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, fail_unreserve: mutex_unlock(&v3d->sched_lock); - v3d_unlock_bo_reservations(dev, job->bo, bo_count, &acquire_ctx); + v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); fail: v3d_tfu_job_put(job); From 62d1a752874962f072de8a779e960fcd2ab4847b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 28 Nov 2018 15:09:27 -0800 Subject: [PATCH 21/31] drm/v3d: Fix prime imports of buffers from other drivers. v3d_bo_get_pages() checks this to decide to map the imported buffer instead of the backing shmem file. The caller was about to set this value anyway, and there's no error path in between. Ideally we wouldn't even allocate the shmem file for our imports, but that's a more invasive fix. Signed-off-by: Eric Anholt Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+") Link: https://patchwork.freedesktop.org/patch/msgid/20181128230927.10951-3-eric@anholt.net Acked-by: Daniel Vetter Reviewed-by: Dave Emett --- drivers/gpu/drm/v3d/v3d_bo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c index 54d96518a131..a08766d39eab 100644 --- a/drivers/gpu/drm/v3d/v3d_bo.c +++ b/drivers/gpu/drm/v3d/v3d_bo.c @@ -293,6 +293,7 @@ v3d_prime_import_sg_table(struct drm_device *dev, bo->resv = attach->dmabuf->resv; bo->sgt = sgt; + obj->import_attach = attach; v3d_bo_get_pages(bo); v3d_mmu_insert_ptes(bo); From 3a936bc2869667d7768f2266d14c4c49a849ffbe Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 28 Nov 2018 11:07:34 +0100 Subject: [PATCH 22/31] drm/meson: Fix an Alpha Primary Plane bug on Meson GXL/GXM SoCs On the Amlogic GXL & GXM SoCs, a bug occurs on the primary plane when alpha is used where the alpha is not aligned with the pixel content. The workaround Amlogic implemented is to reset the OSD1 plane hardware block each time the plane is (re)enabled, solving the issue. In the reset, we still need to save the content of 2 registers which depends on the status of the plane, in addition to reload the scaler conversion matrix at the same time. Signed-off-by: Neil Armstrong Tested-by: Maxime Jourdan Reviewed-by: Maxime Jourdan [narmstrong: fixed typo in commit log] Link: https://patchwork.freedesktop.org/patch/msgid/20181128100734.6536-1-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_plane.c | 12 ++++++++++++ drivers/gpu/drm/meson/meson_viu.c | 27 +++++++++++++++++++++++++++ drivers/gpu/drm/meson/meson_viu.h | 1 + 3 files changed, 40 insertions(+) diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 8ee2cf9e47cd..6119a0224278 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -80,6 +80,7 @@ struct meson_plane { struct drm_plane base; struct meson_drm *priv; + bool enabled; }; #define to_meson_plane(x) container_of(x, struct meson_plane, base) @@ -304,6 +305,15 @@ static void meson_plane_atomic_update(struct drm_plane *plane, priv->viu.osd1_stride = fb->pitches[0]; priv->viu.osd1_height = fb->height; + if (!meson_plane->enabled) { + /* Reset OSD1 before enabling it on GXL+ SoCs */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_viu_osd1_reset(priv); + + meson_plane->enabled = true; + } + spin_unlock_irqrestore(&priv->drm->event_lock, flags); } @@ -317,6 +327,8 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, priv->io_base + _REG(VPP_MISC)); + meson_plane->enabled = false; + } static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 2dffb987ec65..0ba87ff95530 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -296,6 +296,33 @@ static void meson_viu_load_matrix(struct meson_drm *priv) true); } +/* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */ +void meson_viu_osd1_reset(struct meson_drm *priv) +{ + uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2; + + /* Save these 2 registers state */ + osd1_fifo_ctrl_stat = readl_relaxed( + priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); + osd1_ctrl_stat2 = readl_relaxed( + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); + + /* Reset OSD1 */ + writel_bits_relaxed(BIT(0), BIT(0), + priv->io_base + _REG(VIU_SW_RESET)); + writel_bits_relaxed(BIT(0), 0, + priv->io_base + _REG(VIU_SW_RESET)); + + /* Rewrite these registers state lost in the reset */ + writel_relaxed(osd1_fifo_ctrl_stat, + priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); + writel_relaxed(osd1_ctrl_stat2, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); + + /* Reload the conversion matrix */ + meson_viu_load_matrix(priv); +} + void meson_viu_init(struct meson_drm *priv) { uint32_t reg; diff --git a/drivers/gpu/drm/meson/meson_viu.h b/drivers/gpu/drm/meson/meson_viu.h index 073b1910bd1b..0f84bddd2ff0 100644 --- a/drivers/gpu/drm/meson/meson_viu.h +++ b/drivers/gpu/drm/meson/meson_viu.h @@ -59,6 +59,7 @@ #define OSD_REPLACE_EN BIT(14) #define OSD_REPLACE_SHIFT 6 +void meson_viu_osd1_reset(struct meson_drm *priv); void meson_viu_init(struct meson_drm *priv); #endif /* __MESON_VIU_H */ From 4fb86404a977b932eed56c0dd0954f6225eee3eb Mon Sep 17 00:00:00 2001 From: Alex Gonzalez Date: Thu, 25 Oct 2018 17:09:30 +0200 Subject: [PATCH 23/31] drm/panel: simple: Add AUO G101EVN010 panel support The change adds support for the AU Optronics G101EVN010 10.1" TFT LCD panel. Signed-off-by: Alex Gonzalez Reviewed-by: Rob Herring [treding@nvidia.com: sort new entry alphabetically] Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/1540480173-12009-2-git-send-email-alex.gonzalez@digi.com --- .../bindings/display/panel/auo,g101evn010 | 12 +++++++++ drivers/gpu/drm/panel/panel-simple.c | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/auo,g101evn010 diff --git a/Documentation/devicetree/bindings/display/panel/auo,g101evn010 b/Documentation/devicetree/bindings/display/panel/auo,g101evn010 new file mode 100644 index 000000000000..bc6a0c858e23 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/auo,g101evn010 @@ -0,0 +1,12 @@ +AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel + +Required properties: +- compatible: should be "auo,g101evn010" +- power-supply: as specified in the base binding + +Optional properties: +- backlight: as specified in the base binding +- enable-gpios: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5fbee837b0db..9c69e739a524 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -618,6 +618,30 @@ static const struct panel_desc auo_g070vvn01 = { }, }; +static const struct drm_display_mode auo_g101evn010_mode = { + .clock = 68930, + .hdisplay = 1280, + .hsync_start = 1280 + 82, + .hsync_end = 1280 + 82 + 2, + .htotal = 1280 + 82 + 2 + 84, + .vdisplay = 800, + .vsync_start = 800 + 8, + .vsync_end = 800 + 8 + 2, + .vtotal = 800 + 8 + 2 + 6, + .vrefresh = 60, +}; + +static const struct panel_desc auo_g101evn010 = { + .modes = &auo_g101evn010_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 216, + .height = 135, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, +}; + static const struct drm_display_mode auo_g104sn02_mode = { .clock = 40000, .hdisplay = 800, @@ -2493,6 +2517,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "auo,g070vvn01", .data = &auo_g070vvn01, + }, { + .compatible = "auo,g101evn010", + .data = &auo_g101evn010, }, { .compatible = "auo,g104sn02", .data = &auo_g104sn02, From 078dec3326e2244c62e8a8d970ba24359e3464be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 3 Dec 2018 13:36:14 +0100 Subject: [PATCH 24/31] dma-buf: add dma_fence_get_stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract of useful code from the timeline work. This provides a function to return a stub or dummy fence which is always signaled. Signed-off-by: Christian König Reviewed-by: Chris Wilson Reviewed-by: Chunming Zhou Link: https://patchwork.freedesktop.org/patch/265248/ --- drivers/dma-buf/dma-fence.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/dma-fence.h | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 1551ca7df394..136ec04d683f 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -30,13 +30,16 @@ EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit); EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal); +static DEFINE_SPINLOCK(dma_fence_stub_lock); +static struct dma_fence dma_fence_stub; + /* * fence context counter: each execution context should have its own * fence context, this allows checking if fences belong to the same * context or not. One device can have multiple separate contexts, * and they're used if some engine can run independently of another. */ -static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0); +static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1); /** * DOC: DMA fences overview @@ -68,6 +71,37 @@ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0); * &dma_buf.resv pointer. */ +static const char *dma_fence_stub_get_name(struct dma_fence *fence) +{ + return "stub"; +} + +static const struct dma_fence_ops dma_fence_stub_ops = { + .get_driver_name = dma_fence_stub_get_name, + .get_timeline_name = dma_fence_stub_get_name, +}; + +/** + * dma_fence_get_stub - return a signaled fence + * + * Return a stub fence which is already signaled. + */ +struct dma_fence *dma_fence_get_stub(void) +{ + spin_lock(&dma_fence_stub_lock); + if (!dma_fence_stub.ops) { + dma_fence_init(&dma_fence_stub, + &dma_fence_stub_ops, + &dma_fence_stub_lock, + 0, 0); + dma_fence_signal_locked(&dma_fence_stub); + } + spin_unlock(&dma_fence_stub_lock); + + return dma_fence_get(&dma_fence_stub); +} +EXPORT_SYMBOL(dma_fence_get_stub); + /** * dma_fence_context_alloc - allocate an array of fence contexts * @num: amount of contexts to allocate diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 02dba8cd033d..999e4b104410 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -541,6 +541,7 @@ static inline signed long dma_fence_wait(struct dma_fence *fence, bool intr) return ret < 0 ? ret : 0; } +struct dma_fence *dma_fence_get_stub(void); u64 dma_fence_context_alloc(unsigned num); #define DMA_FENCE_TRACE(f, fmt, args...) \ From 86bbd89d5da66fe760049ad3f04adc407ec0c4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 13 Nov 2018 14:14:00 +0100 Subject: [PATCH 25/31] drm/syncobj: use dma_fence_get_stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract of useful code from the timeline work. Let's use just a single stub fence instance instead of allocating a new one all the time. Signed-off-by: Christian König Reviewed-by: Chris Wilson Reviewed-by: Chunming Zhou Link: https://patchwork.freedesktop.org/patch/265248/ --- drivers/gpu/drm/drm_syncobj.c | 58 +++++++++-------------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index e2c5b3ca4824..5c5ba1f14307 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -56,22 +56,6 @@ #include "drm_internal.h" #include -struct drm_syncobj_stub_fence { - struct dma_fence base; - spinlock_t lock; -}; - -static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence) -{ - return "syncobjstub"; -} - -static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { - .get_driver_name = drm_syncobj_stub_fence_get_name, - .get_timeline_name = drm_syncobj_stub_fence_get_name, -}; - - /** * drm_syncobj_find - lookup and reference a sync object. * @file_private: drm file private pointer @@ -190,23 +174,18 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, } EXPORT_SYMBOL(drm_syncobj_replace_fence); -static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) +/** + * drm_syncobj_assign_null_handle - assign a stub fence to the sync object + * @syncobj: sync object to assign the fence on + * + * Assign a already signaled stub fence to the sync object. + */ +static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) { - struct drm_syncobj_stub_fence *fence; - fence = kzalloc(sizeof(*fence), GFP_KERNEL); - if (fence == NULL) - return -ENOMEM; + struct dma_fence *fence = dma_fence_get_stub(); - spin_lock_init(&fence->lock); - dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops, - &fence->lock, 0, 0); - dma_fence_signal(&fence->base); - - drm_syncobj_replace_fence(syncobj, 0, &fence->base); - - dma_fence_put(&fence->base); - - return 0; + drm_syncobj_replace_fence(syncobj, 0, fence); + dma_fence_put(fence); } /** @@ -274,7 +253,6 @@ EXPORT_SYMBOL(drm_syncobj_free); int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, struct dma_fence *fence) { - int ret; struct drm_syncobj *syncobj; syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL); @@ -285,13 +263,8 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, INIT_LIST_HEAD(&syncobj->cb_list); spin_lock_init(&syncobj->lock); - if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { - ret = drm_syncobj_assign_null_handle(syncobj); - if (ret < 0) { - drm_syncobj_put(syncobj); - return ret; - } - } + if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) + drm_syncobj_assign_null_handle(syncobj); if (fence) drm_syncobj_replace_fence(syncobj, 0, fence); @@ -982,11 +955,8 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; - for (i = 0; i < args->count_handles; i++) { - ret = drm_syncobj_assign_null_handle(syncobjs[i]); - if (ret < 0) - break; - } + for (i = 0; i < args->count_handles; i++) + drm_syncobj_assign_null_handle(syncobjs[i]); drm_syncobj_array_free(syncobjs, args->count_handles); From db176f6ba1da39ad0016c77b9775a6bb3d0ce88a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 30 Nov 2018 16:57:59 -0800 Subject: [PATCH 26/31] drm/v3d: Add missing fence timeline name for TFU. We shouldn't be returning v3d-render for our new queue. Signed-off-by: Eric Anholt Fixes: 83d5139982db ("drm/v3d: Add support for submitting jobs to the TFU.") Link: https://patchwork.freedesktop.org/patch/msgid/20181201005759.28093-6-eric@anholt.net Reviewed-by: Dave Emett --- drivers/gpu/drm/v3d/v3d_fence.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_fence.c b/drivers/gpu/drm/v3d/v3d_fence.c index 50bfcf9a8a1a..b0a2a1ae2eb1 100644 --- a/drivers/gpu/drm/v3d/v3d_fence.c +++ b/drivers/gpu/drm/v3d/v3d_fence.c @@ -29,10 +29,16 @@ static const char *v3d_fence_get_timeline_name(struct dma_fence *fence) { struct v3d_fence *f = to_v3d_fence(fence); - if (f->queue == V3D_BIN) + switch (f->queue) { + case V3D_BIN: return "v3d-bin"; - else + case V3D_RENDER: return "v3d-render"; + case V3D_TFU: + return "v3d-tfu"; + default: + return NULL; + } } const struct dma_fence_ops v3d_fence_ops = { From 55a9b74846ed5e6219c7d81a8e1bf96f25d8ad5e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 30 Nov 2018 16:57:58 -0800 Subject: [PATCH 27/31] drm/v3d: Add more tracepoints for V3D GPU rendering. The core scheduler tells us when the job is pushed to the scheduler's queue, and I had the job_run functions saying when they actually queue the job to the hardware. By adding tracepoints for the very top of the ioctls and the IRQs signaling job completion, "perf record -a -e v3d:.\* -e gpu_scheduler:.\* ; perf script" gets you a pretty decent timeline. Signed-off-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20181201005759.28093-5-eric@anholt.net Reviewed-by: Dave Emett --- drivers/gpu/drm/v3d/v3d_gem.c | 4 ++ drivers/gpu/drm/v3d/v3d_irq.c | 19 +++++- drivers/gpu/drm/v3d/v3d_trace.h | 101 ++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 8b4af512450f..f565b197cba9 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -521,6 +521,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, struct drm_syncobj *sync_out; int ret = 0; + trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); + if (args->pad != 0) { DRM_INFO("pad must be zero: %d\n", args->pad); return -EINVAL; @@ -648,6 +650,8 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, int ret = 0; int bo_count; + trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); + job = kcalloc(1, sizeof(*job), GFP_KERNEL); if (!job) return -ENOMEM; diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c index dd7a7b0bd5a1..69338da70ddc 100644 --- a/drivers/gpu/drm/v3d/v3d_irq.c +++ b/drivers/gpu/drm/v3d/v3d_irq.c @@ -15,6 +15,7 @@ #include "v3d_drv.h" #include "v3d_regs.h" +#include "v3d_trace.h" #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ V3D_INT_FLDONE | \ @@ -88,12 +89,20 @@ v3d_irq(int irq, void *arg) } if (intsts & V3D_INT_FLDONE) { - dma_fence_signal(v3d->bin_job->bin.done_fence); + struct v3d_fence *fence = + to_v3d_fence(v3d->bin_job->bin.done_fence); + + trace_v3d_bcl_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); status = IRQ_HANDLED; } if (intsts & V3D_INT_FRDONE) { - dma_fence_signal(v3d->render_job->render.done_fence); + struct v3d_fence *fence = + to_v3d_fence(v3d->render_job->render.done_fence); + + trace_v3d_rcl_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); status = IRQ_HANDLED; } @@ -119,7 +128,11 @@ v3d_hub_irq(int irq, void *arg) V3D_WRITE(V3D_HUB_INT_CLR, intsts); if (intsts & V3D_HUB_INT_TFUC) { - dma_fence_signal(v3d->tfu_job->done_fence); + struct v3d_fence *fence = + to_v3d_fence(v3d->tfu_job->done_fence); + + trace_v3d_tfu_irq(&v3d->drm, fence->seqno); + dma_fence_signal(&fence->base); status = IRQ_HANDLED; } diff --git a/drivers/gpu/drm/v3d/v3d_trace.h b/drivers/gpu/drm/v3d/v3d_trace.h index f54ed9cd3444..edd984afa33f 100644 --- a/drivers/gpu/drm/v3d/v3d_trace.h +++ b/drivers/gpu/drm/v3d/v3d_trace.h @@ -12,6 +12,28 @@ #define TRACE_SYSTEM v3d #define TRACE_INCLUDE_FILE v3d_trace +TRACE_EVENT(v3d_submit_cl_ioctl, + TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea), + TP_ARGS(dev, ct1qba, ct1qea), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u32, ct1qba) + __field(u32, ct1qea) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->ct1qba = ct1qba; + __entry->ct1qea = ct1qea; + ), + + TP_printk("dev=%u, RCL 0x%08x..0x%08x", + __entry->dev, + __entry->ct1qba, + __entry->ct1qea) +); + TRACE_EVENT(v3d_submit_cl, TP_PROTO(struct drm_device *dev, bool is_render, uint64_t seqno, @@ -42,6 +64,85 @@ TRACE_EVENT(v3d_submit_cl, __entry->ctnqea) ); +TRACE_EVENT(v3d_bcl_irq, + TP_PROTO(struct drm_device *dev, + uint64_t seqno), + TP_ARGS(dev, seqno), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u64, seqno) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->seqno = seqno; + ), + + TP_printk("dev=%u, seqno=%llu", + __entry->dev, + __entry->seqno) +); + +TRACE_EVENT(v3d_rcl_irq, + TP_PROTO(struct drm_device *dev, + uint64_t seqno), + TP_ARGS(dev, seqno), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u64, seqno) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->seqno = seqno; + ), + + TP_printk("dev=%u, seqno=%llu", + __entry->dev, + __entry->seqno) +); + +TRACE_EVENT(v3d_tfu_irq, + TP_PROTO(struct drm_device *dev, + uint64_t seqno), + TP_ARGS(dev, seqno), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u64, seqno) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->seqno = seqno; + ), + + TP_printk("dev=%u, seqno=%llu", + __entry->dev, + __entry->seqno) +); + +TRACE_EVENT(v3d_submit_tfu_ioctl, + TP_PROTO(struct drm_device *dev, u32 iia), + TP_ARGS(dev, iia), + + TP_STRUCT__entry( + __field(u32, dev) + __field(u32, iia) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->iia = iia; + ), + + TP_printk("dev=%u, IIA 0x%08x", + __entry->dev, + __entry->iia) +); + TRACE_EVENT(v3d_submit_tfu, TP_PROTO(struct drm_device *dev, uint64_t seqno), From 97f2930f5b13585c9f151cedca021be110804cc3 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 4 Nov 2018 19:26:45 +0100 Subject: [PATCH 28/31] drm/sun4i: Add compatible for H6 display engine H6 is first Allwinner SoC which supports 10 bit colors, HDR and AFBC. Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20181104182705.18047-9-jernej.skrabec@siol.net --- drivers/gpu/drm/sun4i/sun4i_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index ccdeae6299eb..9e4c375ccc96 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -410,6 +410,7 @@ static const struct of_device_id sun4i_drv_of_table[] = { { .compatible = "allwinner,sun8i-v3s-display-engine" }, { .compatible = "allwinner,sun9i-a80-display-engine" }, { .compatible = "allwinner,sun50i-a64-display-engine" }, + { .compatible = "allwinner,sun50i-h6-display-engine" }, { } }; MODULE_DEVICE_TABLE(of, sun4i_drv_of_table); From 77e9c35acd5f9ebc5ab211785e25da880ccdd5fc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 1 Dec 2018 03:20:44 +0000 Subject: [PATCH 29/31] drm/vkms: Remove set but not used variable 'vkms_obj' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpu/drm/vkms/vkms_plane.c: In function 'vkms_prepare_fb': drivers/gpu/drm/vkms/vkms_plane.c:144:26: warning: variable 'vkms_obj' set but not used [-Wunused-but-set-variable] It never used since introduction in commit 8ce1bb0b5337 ("drm/vkms: map/unmap buffers in [prepare/cleanup]_fb hooks") Signed-off-by: YueHaibing Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1543634444-186448-1-git-send-email-yuehaibing@huawei.com --- drivers/gpu/drm/vkms/vkms_plane.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index e3bcea4b4891..418817600ad1 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -141,14 +141,12 @@ static int vkms_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_gem_object *gem_obj; - struct vkms_gem_object *vkms_obj; int ret; if (!state->fb) return 0; gem_obj = drm_gem_fb_get_obj(state->fb, 0); - vkms_obj = drm_gem_to_vkms_gem(gem_obj); ret = vkms_gem_vmap(gem_obj); if (ret) DRM_ERROR("vmap failed: %d\n", ret); From 5ff75c489ce0466744684f5a549dd79f4ba697ca Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 29 Nov 2018 06:00:33 +0000 Subject: [PATCH 30/31] drm/tinydrm: Use kmemdup rather than duplicating its implementation in repaper_spi_transfer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit use kmemdup rather than duplicating its implementation Signed-off-by: YueHaibing Signed-off-by: Noralf Trønnes Link: https://patchwork.freedesktop.org/patch/msgid/1543471233-159568-1-git-send-email-yuehaibing@huawei.com --- drivers/gpu/drm/tinydrm/repaper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tinydrm/repaper.c b/drivers/gpu/drm/tinydrm/repaper.c index 07f45a008a0f..54d6fe0f37ce 100644 --- a/drivers/gpu/drm/tinydrm/repaper.c +++ b/drivers/gpu/drm/tinydrm/repaper.c @@ -108,12 +108,11 @@ static int repaper_spi_transfer(struct spi_device *spi, u8 header, /* Stack allocated tx? */ if (tx && len <= 32) { - txbuf = kmalloc(len, GFP_KERNEL); + txbuf = kmemdup(tx, len, GFP_KERNEL); if (!txbuf) { ret = -ENOMEM; goto out_free; } - memcpy(txbuf, tx, len); } if (rx) { From 0b258ed1a219a9776e8f6967eb34837ae0332e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 14 Nov 2018 14:24:27 +0100 Subject: [PATCH 31/31] drm: revert "expand replace_fence to support timeline point v2" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9a09a42369a4a37a959c051d8e1a1f948c1529a4. The whole interface isn't thought through. Since this function can't fail we actually can't allocate an object to store the sync point. Sorry, I should have taken the lead on this from the very beginning and reviewed it more thoughtfully. Going to propose a new interface as a follow up change. Signed-off-by: Christian König Reviewed-by: Chunming Zhou Link: https://patchwork.freedesktop.org/patch/265580/ --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/drm_syncobj.c | 14 ++++++-------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/v3d/v3d_gem.c | 3 +-- drivers/gpu/drm/vc4/vc4_gem.c | 2 +- include/drm/drm_syncobj.h | 2 +- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 024dfbd87f11..dc54e9efd910 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1193,7 +1193,7 @@ static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p) int i; for (i = 0; i < p->num_post_dep_syncobjs; ++i) - drm_syncobj_replace_fence(p->post_dep_syncobjs[i], 0, p->fence); + drm_syncobj_replace_fence(p->post_dep_syncobjs[i], p->fence); } static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 5c5ba1f14307..db30a0e89db8 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -140,13 +140,11 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj, /** * drm_syncobj_replace_fence - replace fence in a sync object. * @syncobj: Sync object to replace fence in - * @point: timeline point * @fence: fence to install in sync file. * - * This replaces the fence on a sync object, or a timeline point fence. + * This replaces the fence on a sync object. */ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, - u64 point, struct dma_fence *fence) { struct dma_fence *old_fence; @@ -184,7 +182,7 @@ static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) { struct dma_fence *fence = dma_fence_get_stub(); - drm_syncobj_replace_fence(syncobj, 0, fence); + drm_syncobj_replace_fence(syncobj, fence); dma_fence_put(fence); } @@ -233,7 +231,7 @@ void drm_syncobj_free(struct kref *kref) struct drm_syncobj *syncobj = container_of(kref, struct drm_syncobj, refcount); - drm_syncobj_replace_fence(syncobj, 0, NULL); + drm_syncobj_replace_fence(syncobj, NULL); kfree(syncobj); } EXPORT_SYMBOL(drm_syncobj_free); @@ -267,7 +265,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, drm_syncobj_assign_null_handle(syncobj); if (fence) - drm_syncobj_replace_fence(syncobj, 0, fence); + drm_syncobj_replace_fence(syncobj, fence); *out_syncobj = syncobj; return 0; @@ -452,7 +450,7 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private, return -ENOENT; } - drm_syncobj_replace_fence(syncobj, 0, fence); + drm_syncobj_replace_fence(syncobj, fence); dma_fence_put(fence); drm_syncobj_put(syncobj); return 0; @@ -923,7 +921,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data, return ret; for (i = 0; i < args->count_handles; i++) - drm_syncobj_replace_fence(syncobjs[i], 0, NULL); + drm_syncobj_replace_fence(syncobjs[i], NULL); drm_syncobj_array_free(syncobjs, args->count_handles); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d4fac09095f8..10a4afb4f235 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -2191,7 +2191,7 @@ signal_fence_array(struct i915_execbuffer *eb, if (!(flags & I915_EXEC_FENCE_SIGNAL)) continue; - drm_syncobj_replace_fence(syncobj, 0, fence); + drm_syncobj_replace_fence(syncobj, fence); } } diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index f565b197cba9..cb99e53f7607 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -609,8 +609,7 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, /* Update the return sync object for the */ sync_out = drm_syncobj_find(file_priv, args->out_sync); if (sync_out) { - drm_syncobj_replace_fence(sync_out, 0, - exec->render_done_fence); + drm_syncobj_replace_fence(sync_out, exec->render_done_fence); drm_syncobj_put(sync_out); } diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 41881ce4132d..aea2b8dfec17 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -681,7 +681,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec, exec->fence = &fence->base; if (out_sync) - drm_syncobj_replace_fence(out_sync, 0, exec->fence); + drm_syncobj_replace_fence(out_sync, exec->fence); vc4_update_bo_seqnos(exec, seqno); diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h index 2eda44def639..b1fe921f8e8f 100644 --- a/include/drm/drm_syncobj.h +++ b/include/drm/drm_syncobj.h @@ -131,7 +131,7 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj) struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, u32 handle); -void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, +void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, struct dma_fence *fence); int drm_syncobj_find_fence(struct drm_file *file_private, u32 handle, u64 point, u64 flags,