From patchwork Thu Sep 1 20:18:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Hellstrom X-Patchwork-Id: 1120542 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p81KMvi7017402 for ; Thu, 1 Sep 2011 20:23:17 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 35D30A129C for ; Thu, 1 Sep 2011 13:22:57 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from smtp-outbound-2.vmware.com (smtp-outbound-2.vmware.com [65.115.85.73]) by gabe.freedesktop.org (Postfix) with ESMTP id B4356A12B9 for ; Thu, 1 Sep 2011 13:19:11 -0700 (PDT) Received: from mailhost4.vmware.com (mailhost4.vmware.com [10.16.67.124]) by smtp-outbound-2.vmware.com (Postfix) with ESMTP id 96CB25700F; Thu, 1 Sep 2011 13:19:11 -0700 (PDT) Received: from vmlin1.localdomain (unknown [10.23.99.1]) by mailhost4.vmware.com (Postfix) with ESMTP id 48050CA11A; Thu, 1 Sep 2011 13:19:10 -0700 (PDT) From: Thomas Hellstrom To: airlied@gmail.com, dri-devel@lists.freedesktop.org Subject: [PATCH 5/8] vmwgfx: Fix confusion caused by using "fence" in various places Date: Thu, 1 Sep 2011 22:18:42 +0200 Message-Id: <1314908325-2895-6-git-send-email-thellstrom@vmware.com> X-Mailer: git-send-email 1.7.4.4 In-Reply-To: <1314908325-2895-1-git-send-email-thellstrom@vmware.com> References: <1314908325-2895-1-git-send-email-thellstrom@vmware.com> X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 01 Sep 2011 20:23:17 +0000 (UTC) This is needed before we introduce the fence objects. Otherwise this will be even more confusing. The plan is to use the following: seqno: A 32-bit sequence number that may be passed in the fifo. marker: Objects, carrying a seqno, that track fifo submission time. They are used for fifo lag based throttling. fence objects: Kernel space objects, possibly accessible from user-space and carrying a 32-bit seqno together with signaled status. Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz --- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 8 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 42 ++++---- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 173 ------------------------------- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 26 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 56 +++++----- drivers/gpu/drm/vmwgfx/vmwgfx_marker.c | 171 ++++++++++++++++++++++++++++++ include/drm/vmwgfx_drm.h | 6 +- 10 files changed, 247 insertions(+), 249 deletions(-) delete mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_fence.c create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_marker.c diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index c9281a1..f41e8b4 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ - vmwgfx_overlay.o vmwgfx_fence.o vmwgfx_gmrid_manager.o + vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 87e43e0..72d9561 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -295,18 +295,18 @@ static int vmw_sync_obj_flush(void *sync_obj, void *sync_arg) static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg) { struct vmw_private *dev_priv = (struct vmw_private *)sync_arg; - uint32_t sequence = (unsigned long) sync_obj; + uint32_t seqno = (unsigned long) sync_obj; - return vmw_fence_signaled(dev_priv, sequence); + return vmw_seqno_passed(dev_priv, seqno); } static int vmw_sync_obj_wait(void *sync_obj, void *sync_arg, bool lazy, bool interruptible) { struct vmw_private *dev_priv = (struct vmw_private *)sync_arg; - uint32_t sequence = (unsigned long) sync_obj; + uint32_t seqno = (unsigned long) sync_obj; - return vmw_wait_fence(dev_priv, false, sequence, false, 3*HZ); + return vmw_wait_seqno(dev_priv, false, seqno, false, 3*HZ); } struct ttm_bo_driver vmw_bo_driver = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8010254..c8b5a53 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -280,7 +280,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->dev = dev; dev_priv->vmw_chipset = chipset; - dev_priv->last_read_sequence = (uint32_t) -100; + dev_priv->last_read_seqno = (uint32_t) -100; mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->release_mutex); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 2374a5c..9c3016b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -105,7 +105,7 @@ struct vmw_surface { struct vmw_cursor_snooper snooper; }; -struct vmw_fence_queue { +struct vmw_marker_queue { struct list_head head; struct timespec lag; struct timespec lag_time; @@ -121,7 +121,7 @@ struct vmw_fifo_state { uint32_t capabilities; struct mutex fifo_mutex; struct rw_semaphore rwsem; - struct vmw_fence_queue fence_queue; + struct vmw_marker_queue marker_queue; }; struct vmw_relocation { @@ -238,12 +238,12 @@ struct vmw_private { * Fencing and IRQs. */ - atomic_t fence_seq; + atomic_t marker_seq; wait_queue_head_t fence_queue; wait_queue_head_t fifo_queue; atomic_t fence_queue_waiters; atomic_t fifo_queue_waiters; - uint32_t last_read_sequence; + uint32_t last_read_seqno; spinlock_t irq_lock; /* @@ -411,7 +411,7 @@ extern void vmw_fifo_release(struct vmw_private *dev_priv, extern void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes); extern void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes); extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, - uint32_t *sequence); + uint32_t *seqno); extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason); extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); @@ -448,39 +448,39 @@ extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data, */ extern irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS); -extern int vmw_wait_fence(struct vmw_private *dev_priv, bool lazy, - uint32_t sequence, bool interruptible, - unsigned long timeout); +extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy, + uint32_t seqno, bool interruptible, + unsigned long timeout); extern void vmw_irq_preinstall(struct drm_device *dev); extern int vmw_irq_postinstall(struct drm_device *dev); extern void vmw_irq_uninstall(struct drm_device *dev); -extern bool vmw_fence_signaled(struct vmw_private *dev_priv, - uint32_t sequence); +extern bool vmw_seqno_passed(struct vmw_private *dev_priv, + uint32_t seqno); extern int vmw_fence_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int vmw_fallback_wait(struct vmw_private *dev_priv, bool lazy, bool fifo_idle, - uint32_t sequence, + uint32_t seqno, bool interruptible, unsigned long timeout); -extern void vmw_update_sequence(struct vmw_private *dev_priv, +extern void vmw_update_seqno(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo_state); /** - * Rudimentary fence objects currently used only for throttling - - * vmwgfx_fence.c + * Rudimentary fence-like objects currently used only for throttling - + * vmwgfx_marker.c */ -extern void vmw_fence_queue_init(struct vmw_fence_queue *queue); -extern void vmw_fence_queue_takedown(struct vmw_fence_queue *queue); -extern int vmw_fence_push(struct vmw_fence_queue *queue, - uint32_t sequence); -extern int vmw_fence_pull(struct vmw_fence_queue *queue, - uint32_t signaled_sequence); +extern void vmw_marker_queue_init(struct vmw_marker_queue *queue); +extern void vmw_marker_queue_takedown(struct vmw_marker_queue *queue); +extern int vmw_marker_push(struct vmw_marker_queue *queue, + uint32_t seqno); +extern int vmw_marker_pull(struct vmw_marker_queue *queue, + uint32_t signaled_seqno); extern int vmw_wait_lag(struct vmw_private *dev_priv, - struct vmw_fence_queue *queue, uint32_t us); + struct vmw_marker_queue *queue, uint32_t us); /** * Kernel framebuffer - vmwgfx_fb.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 3dac8ab..4811c6b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -685,7 +685,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, int ret; void *user_cmd; void *cmd; - uint32_t sequence; + uint32_t seqno; struct vmw_sw_context *sw_context = &dev_priv->ctx; struct vmw_master *vmaster = vmw_master(file_priv->master); @@ -737,7 +737,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, vmw_apply_relocations(sw_context); if (arg->throttle_us) { - ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.fence_queue, + ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, arg->throttle_us); if (unlikely(ret != 0)) @@ -754,10 +754,10 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, memcpy(cmd, sw_context->cmd_bounce, arg->command_size); vmw_fifo_commit(dev_priv, arg->command_size); - ret = vmw_fifo_send_fence(dev_priv, &sequence); + ret = vmw_fifo_send_fence(dev_priv, &seqno); ttm_eu_fence_buffer_objects(&sw_context->validate_nodes, - (void *)(unsigned long) sequence); + (void *)(unsigned long) seqno); vmw_clear_validations(sw_context); mutex_unlock(&dev_priv->cmdbuf_mutex); @@ -770,7 +770,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, DRM_ERROR("Fence submission error. Syncing.\n"); fence_rep.error = ret; - fence_rep.fence_seq = (uint64_t) sequence; + fence_rep.fence_seq = (uint64_t) seqno; fence_rep.pad64 = 0; user_fence_rep = (struct drm_vmw_fence_rep __user *) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c deleted file mode 100644 index 61eacc1..0000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ /dev/null @@ -1,173 +0,0 @@ -/************************************************************************** - * - * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - -#include "vmwgfx_drv.h" - -struct vmw_fence { - struct list_head head; - uint32_t sequence; - struct timespec submitted; -}; - -void vmw_fence_queue_init(struct vmw_fence_queue *queue) -{ - INIT_LIST_HEAD(&queue->head); - queue->lag = ns_to_timespec(0); - getrawmonotonic(&queue->lag_time); - spin_lock_init(&queue->lock); -} - -void vmw_fence_queue_takedown(struct vmw_fence_queue *queue) -{ - struct vmw_fence *fence, *next; - - spin_lock(&queue->lock); - list_for_each_entry_safe(fence, next, &queue->head, head) { - kfree(fence); - } - spin_unlock(&queue->lock); -} - -int vmw_fence_push(struct vmw_fence_queue *queue, - uint32_t sequence) -{ - struct vmw_fence *fence = kmalloc(sizeof(*fence), GFP_KERNEL); - - if (unlikely(!fence)) - return -ENOMEM; - - fence->sequence = sequence; - getrawmonotonic(&fence->submitted); - spin_lock(&queue->lock); - list_add_tail(&fence->head, &queue->head); - spin_unlock(&queue->lock); - - return 0; -} - -int vmw_fence_pull(struct vmw_fence_queue *queue, - uint32_t signaled_sequence) -{ - struct vmw_fence *fence, *next; - struct timespec now; - bool updated = false; - - spin_lock(&queue->lock); - getrawmonotonic(&now); - - if (list_empty(&queue->head)) { - queue->lag = ns_to_timespec(0); - queue->lag_time = now; - updated = true; - goto out_unlock; - } - - list_for_each_entry_safe(fence, next, &queue->head, head) { - if (signaled_sequence - fence->sequence > (1 << 30)) - continue; - - queue->lag = timespec_sub(now, fence->submitted); - queue->lag_time = now; - updated = true; - list_del(&fence->head); - kfree(fence); - } - -out_unlock: - spin_unlock(&queue->lock); - - return (updated) ? 0 : -EBUSY; -} - -static struct timespec vmw_timespec_add(struct timespec t1, - struct timespec t2) -{ - t1.tv_sec += t2.tv_sec; - t1.tv_nsec += t2.tv_nsec; - if (t1.tv_nsec >= 1000000000L) { - t1.tv_sec += 1; - t1.tv_nsec -= 1000000000L; - } - - return t1; -} - -static struct timespec vmw_fifo_lag(struct vmw_fence_queue *queue) -{ - struct timespec now; - - spin_lock(&queue->lock); - getrawmonotonic(&now); - queue->lag = vmw_timespec_add(queue->lag, - timespec_sub(now, queue->lag_time)); - queue->lag_time = now; - spin_unlock(&queue->lock); - return queue->lag; -} - - -static bool vmw_lag_lt(struct vmw_fence_queue *queue, - uint32_t us) -{ - struct timespec lag, cond; - - cond = ns_to_timespec((s64) us * 1000); - lag = vmw_fifo_lag(queue); - return (timespec_compare(&lag, &cond) < 1); -} - -int vmw_wait_lag(struct vmw_private *dev_priv, - struct vmw_fence_queue *queue, uint32_t us) -{ - struct vmw_fence *fence; - uint32_t sequence; - int ret; - - while (!vmw_lag_lt(queue, us)) { - spin_lock(&queue->lock); - if (list_empty(&queue->head)) - sequence = atomic_read(&dev_priv->fence_seq); - else { - fence = list_first_entry(&queue->head, - struct vmw_fence, head); - sequence = fence->sequence; - } - spin_unlock(&queue->lock); - - ret = vmw_wait_fence(dev_priv, false, sequence, true, - 3*HZ); - - if (unlikely(ret != 0)) - return ret; - - (void) vmw_fence_pull(queue, sequence); - } - return 0; -} - - diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index aae01b9..3ba9cac 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -127,9 +127,9 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) (unsigned int) min, (unsigned int) fifo->capabilities); - atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence); - iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE); - vmw_fence_queue_init(&fifo->fence_queue); + atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); + iowrite32(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE); + vmw_marker_queue_init(&fifo->marker_queue); return vmw_fifo_send_fence(dev_priv, &dummy); } @@ -156,7 +156,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); - dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + dev_priv->last_read_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, dev_priv->config_done_state); @@ -166,7 +166,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) dev_priv->traces_state); mutex_unlock(&dev_priv->hw_mutex); - vmw_fence_queue_takedown(&fifo->fence_queue); + vmw_marker_queue_takedown(&fifo->marker_queue); if (likely(fifo->static_buffer != NULL)) { vfree(fifo->static_buffer); @@ -447,7 +447,7 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) mutex_unlock(&fifo_state->fifo_mutex); } -int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) +int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; struct svga_fifo_cmd_fence *cmd_fence; @@ -457,16 +457,16 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) fm = vmw_fifo_reserve(dev_priv, bytes); if (unlikely(fm == NULL)) { - *sequence = atomic_read(&dev_priv->fence_seq); + *seqno = atomic_read(&dev_priv->marker_seq); ret = -ENOMEM; - (void)vmw_fallback_wait(dev_priv, false, true, *sequence, + (void)vmw_fallback_wait(dev_priv, false, true, *seqno, false, 3*HZ); goto out_err; } do { - *sequence = atomic_add_return(1, &dev_priv->fence_seq); - } while (*sequence == 0); + *seqno = atomic_add_return(1, &dev_priv->marker_seq); + } while (*seqno == 0); if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE)) { @@ -483,10 +483,10 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence) cmd_fence = (struct svga_fifo_cmd_fence *) ((unsigned long)fm + sizeof(__le32)); - iowrite32(*sequence, &cmd_fence->fence); + iowrite32(*seqno, &cmd_fence->fence); vmw_fifo_commit(dev_priv, bytes); - (void) vmw_fence_push(&fifo_state->fence_queue, *sequence); - vmw_update_sequence(dev_priv, fifo_state); + (void) vmw_marker_push(&fifo_state->marker_queue, *seqno); + vmw_update_seqno(dev_priv, fifo_state); out_err: return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index e92298a..48701d2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -53,7 +53,7 @@ irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; } -static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) +static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) { uint32_t busy; @@ -64,43 +64,43 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence) return (busy == 0); } -void vmw_update_sequence(struct vmw_private *dev_priv, +void vmw_update_seqno(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo_state) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; - uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE); + uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); - if (dev_priv->last_read_sequence != sequence) { - dev_priv->last_read_sequence = sequence; - vmw_fence_pull(&fifo_state->fence_queue, sequence); + if (dev_priv->last_read_seqno != seqno) { + dev_priv->last_read_seqno = seqno; + vmw_marker_pull(&fifo_state->marker_queue, seqno); } } -bool vmw_fence_signaled(struct vmw_private *dev_priv, - uint32_t sequence) +bool vmw_seqno_passed(struct vmw_private *dev_priv, + uint32_t seqno) { struct vmw_fifo_state *fifo_state; bool ret; - if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) + if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return true; fifo_state = &dev_priv->fifo; - vmw_update_sequence(dev_priv, fifo_state); - if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) + vmw_update_seqno(dev_priv, fifo_state); + if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return true; if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) && - vmw_fifo_idle(dev_priv, sequence)) + vmw_fifo_idle(dev_priv, seqno)) return true; /** - * Then check if the sequence is higher than what we've actually + * Then check if the seqno is higher than what we've actually * emitted. Then the fence is stale and signaled. */ - ret = ((atomic_read(&dev_priv->fence_seq) - sequence) + ret = ((atomic_read(&dev_priv->marker_seq) - seqno) > VMW_FENCE_WRAP); return ret; @@ -109,7 +109,7 @@ bool vmw_fence_signaled(struct vmw_private *dev_priv, int vmw_fallback_wait(struct vmw_private *dev_priv, bool lazy, bool fifo_idle, - uint32_t sequence, + uint32_t seqno, bool interruptible, unsigned long timeout) { @@ -123,7 +123,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, DEFINE_WAIT(__wait); wait_condition = (fifo_idle) ? &vmw_fifo_idle : - &vmw_fence_signaled; + &vmw_seqno_passed; /** * Block command submission while waiting for idle. @@ -131,14 +131,14 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, if (fifo_idle) down_read(&fifo_state->rwsem); - signal_seq = atomic_read(&dev_priv->fence_seq); + signal_seq = atomic_read(&dev_priv->marker_seq); ret = 0; for (;;) { prepare_to_wait(&dev_priv->fence_queue, &__wait, (interruptible) ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (wait_condition(dev_priv, sequence)) + if (wait_condition(dev_priv, seqno)) break; if (time_after_eq(jiffies, end_jiffies)) { DRM_ERROR("SVGA device lockup.\n"); @@ -175,28 +175,28 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, return ret; } -int vmw_wait_fence(struct vmw_private *dev_priv, - bool lazy, uint32_t sequence, - bool interruptible, unsigned long timeout) +int vmw_wait_seqno(struct vmw_private *dev_priv, + bool lazy, uint32_t seqno, + bool interruptible, unsigned long timeout) { long ret; unsigned long irq_flags; struct vmw_fifo_state *fifo = &dev_priv->fifo; - if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP)) + if (likely(dev_priv->last_read_seqno - seqno < VMW_FENCE_WRAP)) return 0; - if (likely(vmw_fence_signaled(dev_priv, sequence))) + if (likely(vmw_seqno_passed(dev_priv, seqno))) return 0; vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC); if (!(fifo->capabilities & SVGA_FIFO_CAP_FENCE)) - return vmw_fallback_wait(dev_priv, lazy, true, sequence, + return vmw_fallback_wait(dev_priv, lazy, true, seqno, interruptible, timeout); if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK)) - return vmw_fallback_wait(dev_priv, lazy, false, sequence, + return vmw_fallback_wait(dev_priv, lazy, false, seqno, interruptible, timeout); mutex_lock(&dev_priv->hw_mutex); @@ -214,12 +214,12 @@ int vmw_wait_fence(struct vmw_private *dev_priv, if (interruptible) ret = wait_event_interruptible_timeout (dev_priv->fence_queue, - vmw_fence_signaled(dev_priv, sequence), + vmw_seqno_passed(dev_priv, seqno), timeout); else ret = wait_event_timeout (dev_priv->fence_queue, - vmw_fence_signaled(dev_priv, sequence), + vmw_seqno_passed(dev_priv, seqno), timeout); if (unlikely(ret == 0)) @@ -293,5 +293,5 @@ int vmw_fence_wait_ioctl(struct drm_device *dev, void *data, return -EBUSY; timeout = (unsigned long)arg->kernel_cookie - timeout; - return vmw_wait_fence(vmw_priv(dev), true, arg->sequence, true, timeout); + return vmw_wait_seqno(vmw_priv(dev), true, arg->seqno, true, timeout); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c new file mode 100644 index 0000000..8a8725c --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c @@ -0,0 +1,171 @@ +/************************************************************************** + * + * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "vmwgfx_drv.h" + +struct vmw_marker { + struct list_head head; + uint32_t seqno; + struct timespec submitted; +}; + +void vmw_marker_queue_init(struct vmw_marker_queue *queue) +{ + INIT_LIST_HEAD(&queue->head); + queue->lag = ns_to_timespec(0); + getrawmonotonic(&queue->lag_time); + spin_lock_init(&queue->lock); +} + +void vmw_marker_queue_takedown(struct vmw_marker_queue *queue) +{ + struct vmw_marker *marker, *next; + + spin_lock(&queue->lock); + list_for_each_entry_safe(marker, next, &queue->head, head) { + kfree(marker); + } + spin_unlock(&queue->lock); +} + +int vmw_marker_push(struct vmw_marker_queue *queue, + uint32_t seqno) +{ + struct vmw_marker *marker = kmalloc(sizeof(*marker), GFP_KERNEL); + + if (unlikely(!marker)) + return -ENOMEM; + + marker->seqno = seqno; + getrawmonotonic(&marker->submitted); + spin_lock(&queue->lock); + list_add_tail(&marker->head, &queue->head); + spin_unlock(&queue->lock); + + return 0; +} + +int vmw_marker_pull(struct vmw_marker_queue *queue, + uint32_t signaled_seqno) +{ + struct vmw_marker *marker, *next; + struct timespec now; + bool updated = false; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + + if (list_empty(&queue->head)) { + queue->lag = ns_to_timespec(0); + queue->lag_time = now; + updated = true; + goto out_unlock; + } + + list_for_each_entry_safe(marker, next, &queue->head, head) { + if (signaled_seqno - marker->seqno > (1 << 30)) + continue; + + queue->lag = timespec_sub(now, marker->submitted); + queue->lag_time = now; + updated = true; + list_del(&marker->head); + kfree(marker); + } + +out_unlock: + spin_unlock(&queue->lock); + + return (updated) ? 0 : -EBUSY; +} + +static struct timespec vmw_timespec_add(struct timespec t1, + struct timespec t2) +{ + t1.tv_sec += t2.tv_sec; + t1.tv_nsec += t2.tv_nsec; + if (t1.tv_nsec >= 1000000000L) { + t1.tv_sec += 1; + t1.tv_nsec -= 1000000000L; + } + + return t1; +} + +static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue) +{ + struct timespec now; + + spin_lock(&queue->lock); + getrawmonotonic(&now); + queue->lag = vmw_timespec_add(queue->lag, + timespec_sub(now, queue->lag_time)); + queue->lag_time = now; + spin_unlock(&queue->lock); + return queue->lag; +} + + +static bool vmw_lag_lt(struct vmw_marker_queue *queue, + uint32_t us) +{ + struct timespec lag, cond; + + cond = ns_to_timespec((s64) us * 1000); + lag = vmw_fifo_lag(queue); + return (timespec_compare(&lag, &cond) < 1); +} + +int vmw_wait_lag(struct vmw_private *dev_priv, + struct vmw_marker_queue *queue, uint32_t us) +{ + struct vmw_marker *marker; + uint32_t seqno; + int ret; + + while (!vmw_lag_lt(queue, us)) { + spin_lock(&queue->lock); + if (list_empty(&queue->head)) + seqno = atomic_read(&dev_priv->marker_seq); + else { + marker = list_first_entry(&queue->head, + struct vmw_marker, head); + seqno = marker->seqno; + } + spin_unlock(&queue->lock); + + ret = vmw_wait_seqno(dev_priv, false, seqno, true, + 3*HZ); + + if (unlikely(ret != 0)) + return ret; + + (void) vmw_marker_pull(queue, seqno); + } + return 0; +} diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h index 467b80c..c2b3909 100644 --- a/include/drm/vmwgfx_drm.h +++ b/include/drm/vmwgfx_drm.h @@ -289,7 +289,7 @@ union drm_vmw_surface_reference_arg { * DRM_VMW_EXECBUF * * Submit a command buffer for execution on the host, and return a - * fence sequence that when signaled, indicates that the command buffer has + * fence seqno that when signaled, indicates that the command buffer has * executed. */ @@ -325,7 +325,7 @@ struct drm_vmw_execbuf_arg { /** * struct drm_vmw_fence_rep * - * @fence_seq: Fence sequence associated with a command submission. + * @fence_seq: Fence seqno associated with a command submission. * @error: This member should've been set to -EFAULT on submission. * The following actions should be take on completion: * error == -EFAULT: Fence communication failed. The host is synchronized. @@ -432,7 +432,7 @@ struct drm_vmw_unref_dmabuf_arg { struct drm_vmw_fence_wait_arg { - uint64_t sequence; + uint64_t seqno; uint64_t kernel_cookie; int32_t cookie_valid; int32_t pad64;