Signed-off-by: Rob Clark <robdclark@xxxxxxxxx> --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_atomic.c | 1 + drivers/gpu/drm/msm/msm_drv.c | 108 +------------------------------- drivers/gpu/drm/msm/msm_drv.h | 27 +------- drivers/gpu/drm/msm/msm_fence.c | 129 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_fence.h | 43 +++++++++++++ drivers/gpu/drm/msm/msm_gem.c | 1 + drivers/gpu/drm/msm/msm_gpu.c | 1 + 8 files changed, 178 insertions(+), 133 deletions(-) create mode 100644 drivers/gpu/drm/msm/msm_fence.c create mode 100644 drivers/gpu/drm/msm/msm_fence.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index cfec4bb..d2d9de8 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -26,6 +26,7 @@ msm-y := \ msm_debugfs.o \ msm_drv.o \ msm_fb.o \ + msm_fence.o \ msm_gem.o \ msm_gem_prime.o \ msm_gem_submit.o \ diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 7eb253b..3c0f7a8 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -18,6 +18,7 @@ #include "msm_drv.h" #include "msm_kms.h" #include "msm_gem.h" +#include "msm_fence.h" struct msm_commit { struct drm_device *dev; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 5e08ea9..6988285 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -17,6 +17,7 @@ #include "msm_drv.h" #include "msm_debugfs.h" +#include "msm_fence.h" #include "msm_gpu.h" #include "msm_kms.h" @@ -540,113 +541,6 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) } /* - * Fences: - */ - -int msm_wait_fence(struct drm_device *dev, uint32_t fence, - ktime_t *timeout , bool interruptible) -{ - struct msm_drm_private *priv = dev->dev_private; - int ret; - - if (!priv->gpu) - return 0; - - if (fence > priv->gpu->submitted_fence) { - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, priv->gpu->submitted_fence); - return -EINVAL; - } - - if (!timeout) { - /* no-wait: */ - ret = fence_completed(dev, fence) ? 0 : -EBUSY; - } else { - ktime_t now = ktime_get(); - unsigned long remaining_jiffies; - - if (ktime_compare(*timeout, now) < 0) { - remaining_jiffies = 0; - } else { - ktime_t rem = ktime_sub(*timeout, now); - struct timespec ts = ktime_to_timespec(rem); - remaining_jiffies = timespec_to_jiffies(&ts); - } - - if (interruptible) - ret = wait_event_interruptible_timeout(priv->fence_event, - fence_completed(dev, fence), - remaining_jiffies); - else - ret = wait_event_timeout(priv->fence_event, - fence_completed(dev, fence), - remaining_jiffies); - - if (ret == 0) { - DBG("timeout waiting for fence: %u (completed: %u)", - fence, priv->completed_fence); - ret = -ETIMEDOUT; - } else if (ret != -ERESTARTSYS) { - ret = 0; - } - } - - return ret; -} - -int msm_queue_fence_cb(struct drm_device *dev, - struct msm_fence_cb *cb, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - int ret = 0; - - mutex_lock(&dev->struct_mutex); - if (!list_empty(&cb->work.entry)) { - ret = -EINVAL; - } else if (fence > priv->completed_fence) { - cb->fence = fence; - list_add_tail(&cb->work.entry, &priv->fence_cbs); - } else { - queue_work(priv->wq, &cb->work); - } - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -/* called from workqueue */ -void msm_update_fence(struct drm_device *dev, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - - mutex_lock(&dev->struct_mutex); - priv->completed_fence = max(fence, priv->completed_fence); - - while (!list_empty(&priv->fence_cbs)) { - struct msm_fence_cb *cb; - - cb = list_first_entry(&priv->fence_cbs, - struct msm_fence_cb, work.entry); - - if (cb->fence > priv->completed_fence) - break; - - list_del_init(&cb->work.entry); - queue_work(priv->wq, &cb->work); - } - - mutex_unlock(&dev->struct_mutex); - - wake_up_all(&priv->fence_event); -} - -void __msm_fence_worker(struct work_struct *work) -{ - struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); - cb->func(cb); -} - -/* * DRM ioctls: */ diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 6980aa4..dfd8c8b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -49,6 +49,7 @@ struct msm_mmu; struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; +struct msm_fence_cb; #define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ @@ -157,20 +158,6 @@ struct msm_format { uint32_t pixel_format; }; -/* callback from wq once fence has passed: */ -struct msm_fence_cb { - struct work_struct work; - uint32_t fence; - void (*func)(struct msm_fence_cb *cb); -}; - -void __msm_fence_worker(struct work_struct *work); - -#define INIT_FENCE_CB(_cb, _func) do { \ - INIT_WORK(&(_cb)->work, __msm_fence_worker); \ - (_cb)->func = _func; \ - } while (0) - int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state); int msm_atomic_commit(struct drm_device *dev, @@ -178,12 +165,6 @@ int msm_atomic_commit(struct drm_device *dev, int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); -int msm_wait_fence(struct drm_device *dev, uint32_t fence, - ktime_t *timeout, bool interruptible); -int msm_queue_fence_cb(struct drm_device *dev, - struct msm_fence_cb *cb, uint32_t fence); -void msm_update_fence(struct drm_device *dev, uint32_t fence); - int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); @@ -336,12 +317,6 @@ u32 msm_readl(const void __iomem *addr); #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) -static inline bool fence_completed(struct drm_device *dev, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - return priv->completed_fence >= fence; -} - static inline int align_pitch(int width, int bpp) { int bytespp = (bpp + 7) / 8; diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c new file mode 100644 index 0000000..55a5f92 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013-2016 Red Hat + * Author: Rob Clark <robdclark@xxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_fence.h" +#include "msm_gpu.h" + +static inline bool fence_completed(struct drm_device *dev, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + return (int32_t)(priv->completed_fence - fence) >= 0; +} + +int msm_wait_fence(struct drm_device *dev, uint32_t fence, + ktime_t *timeout , bool interruptible) +{ + struct msm_drm_private *priv = dev->dev_private; + int ret; + + if (!priv->gpu) + return 0; + + if (fence > priv->gpu->submitted_fence) { + DRM_ERROR("waiting on invalid fence: %u (of %u)\n", + fence, priv->gpu->submitted_fence); + return -EINVAL; + } + + if (!timeout) { + /* no-wait: */ + ret = fence_completed(dev, fence) ? 0 : -EBUSY; + } else { + ktime_t now = ktime_get(); + unsigned long remaining_jiffies; + + if (ktime_compare(*timeout, now) < 0) { + remaining_jiffies = 0; + } else { + ktime_t rem = ktime_sub(*timeout, now); + struct timespec ts = ktime_to_timespec(rem); + remaining_jiffies = timespec_to_jiffies(&ts); + } + + if (interruptible) + ret = wait_event_interruptible_timeout(priv->fence_event, + fence_completed(dev, fence), + remaining_jiffies); + else + ret = wait_event_timeout(priv->fence_event, + fence_completed(dev, fence), + remaining_jiffies); + + if (ret == 0) { + DBG("timeout waiting for fence: %u (completed: %u)", + fence, priv->completed_fence); + ret = -ETIMEDOUT; + } else if (ret != -ERESTARTSYS) { + ret = 0; + } + } + + return ret; +} + +int msm_queue_fence_cb(struct drm_device *dev, + struct msm_fence_cb *cb, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + if (!list_empty(&cb->work.entry)) { + ret = -EINVAL; + } else if (fence > priv->completed_fence) { + cb->fence = fence; + list_add_tail(&cb->work.entry, &priv->fence_cbs); + } else { + queue_work(priv->wq, &cb->work); + } + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +/* called from workqueue */ +void msm_update_fence(struct drm_device *dev, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + priv->completed_fence = max(fence, priv->completed_fence); + + while (!list_empty(&priv->fence_cbs)) { + struct msm_fence_cb *cb; + + cb = list_first_entry(&priv->fence_cbs, + struct msm_fence_cb, work.entry); + + if (cb->fence > priv->completed_fence) + break; + + list_del_init(&cb->work.entry); + queue_work(priv->wq, &cb->work); + } + + mutex_unlock(&dev->struct_mutex); + + wake_up_all(&priv->fence_event); +} + +void __msm_fence_worker(struct work_struct *work) +{ + struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); + cb->func(cb); +} diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h new file mode 100644 index 0000000..6ddb81c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013-2016 Red Hat + * Author: Rob Clark <robdclark@xxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_FENCE_H__ +#define __MSM_FENCE_H__ + +#include "msm_drv.h" + +/* callback from wq once fence has passed: */ +struct msm_fence_cb { + struct work_struct work; + uint32_t fence; + void (*func)(struct msm_fence_cb *cb); +}; + +void __msm_fence_worker(struct work_struct *work); + +#define INIT_FENCE_CB(_cb, _func) do { \ + INIT_WORK(&(_cb)->work, __msm_fence_worker); \ + (_cb)->func = _func; \ + } while (0) + +int msm_wait_fence(struct drm_device *dev, uint32_t fence, + ktime_t *timeout, bool interruptible); +int msm_queue_fence_cb(struct drm_device *dev, + struct msm_fence_cb *cb, uint32_t fence); +void msm_update_fence(struct drm_device *dev, uint32_t fence); + +#endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 3cedb8d..ef03ee7 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -21,6 +21,7 @@ #include <linux/pfn_t.h> #include "msm_drv.h" +#include "msm_fence.h" #include "msm_gem.h" #include "msm_gpu.h" #include "msm_mmu.h" diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 42e2284..5f6704c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -18,6 +18,7 @@ #include "msm_gpu.h" #include "msm_gem.h" #include "msm_mmu.h" +#include "msm_fence.h" /* -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html