Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca762a8a authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm: introduce msm_fence_context



Better encapsulate the per-timeline stuff into fence-context.  For now
there is just a single fence-context, but eventually we'll also have one
per-CRTC to enable fully explicit fencing.

Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 340faef2
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ void adreno_recover(struct msm_gpu *gpu)
	gpu->rb->cur = gpu->rb->start;

	/* reset completed fence seqno, just discard anything pending: */
	adreno_gpu->memptrs->fence = gpu->submitted_fence;
	adreno_gpu->memptrs->fence = gpu->fctx->last_fence;
	adreno_gpu->memptrs->rptr  = 0;
	adreno_gpu->memptrs->wptr  = 0;

@@ -254,7 +254,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
			adreno_gpu->rev.patchid);

	seq_printf(m, "fence:    %d/%d\n", adreno_gpu->memptrs->fence,
			gpu->submitted_fence);
			gpu->fctx->last_fence);
	seq_printf(m, "rptr:     %d\n", get_rptr(adreno_gpu));
	seq_printf(m, "wptr:     %d\n", adreno_gpu->memptrs->wptr);
	seq_printf(m, "rb wptr:  %d\n", get_wptr(gpu->rb));
@@ -295,7 +295,7 @@ void adreno_dump_info(struct msm_gpu *gpu)
			adreno_gpu->rev.patchid);

	printk("fence:    %d/%d\n", adreno_gpu->memptrs->fence,
			gpu->submitted_fence);
			gpu->fctx->last_fence);
	printk("rptr:     %d\n", get_rptr(adreno_gpu));
	printk("wptr:     %d\n", adreno_gpu->memptrs->wptr);
	printk("rb wptr:  %d\n", get_wptr(gpu->rb));
+6 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "msm_drv.h"
#include "msm_kms.h"
#include "msm_gem.h"
#include "msm_gpu.h"   /* temporary */
#include "msm_fence.h"

struct msm_commit {
@@ -202,6 +203,7 @@ int msm_atomic_check(struct drm_device *dev,
int msm_atomic_commit(struct drm_device *dev,
		struct drm_atomic_state *state, bool nonblock)
{
	struct msm_drm_private *priv = dev->dev_private;
	int nplanes = dev->mode_config.num_total_plane;
	int ncrtcs = dev->mode_config.num_crtc;
	ktime_t timeout;
@@ -276,15 +278,16 @@ int msm_atomic_commit(struct drm_device *dev,
	 * current layout.
	 */

	if (nonblock) {
		msm_queue_fence_cb(dev, &c->fence_cb, c->fence);
	if (nonblock && priv->gpu) {
		msm_queue_fence_cb(priv->gpu->fctx, &c->fence_cb, c->fence);
		return 0;
	}

	timeout = ktime_add_ms(ktime_get(), 1000);

	/* uninterruptible wait */
	msm_wait_fence(dev, c->fence, &timeout, false);
	if (priv->gpu)
		msm_wait_fence(priv->gpu->fctx, c->fence, &timeout, false);

	complete_commit(c);

+5 −3
Original line number Diff line number Diff line
@@ -339,11 +339,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
	dev->dev_private = priv;

	priv->wq = alloc_ordered_workqueue("msm", 0);
	init_waitqueue_head(&priv->fence_event);
	init_waitqueue_head(&priv->pending_crtcs_event);

	INIT_LIST_HEAD(&priv->inactive_list);
	INIT_LIST_HEAD(&priv->fence_cbs);
	INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
	INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker);
	spin_lock_init(&priv->vblank_ctrl.lock);
@@ -647,6 +645,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
		struct drm_file *file)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct drm_msm_wait_fence *args = data;
	ktime_t timeout = to_ktime(args->timeout);

@@ -655,7 +654,10 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
		return -EINVAL;
	}

	return msm_wait_fence(dev, args->fence, &timeout, true);
	if (!priv->gpu)
		return 0;

	return msm_wait_fence(priv->gpu->fctx, args->fence, &timeout, true);
}

static const struct drm_ioctl_desc msm_ioctls[] = {
+1 −8
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ struct msm_mmu;
struct msm_rd_state;
struct msm_perf_state;
struct msm_gem_submit;
struct msm_fence_context;
struct msm_fence_cb;

#define NUM_DOMAINS 2    /* one for KMS, then one per gpu core (?) */
@@ -101,9 +102,6 @@ struct msm_drm_private {

	struct drm_fb_helper *fbdev;

	uint32_t next_fence, completed_fence;
	wait_queue_head_t fence_event;

	struct msm_rd_state *rd;
	struct msm_perf_state *perf;

@@ -112,9 +110,6 @@ struct msm_drm_private {

	struct workqueue_struct *wq;

	/* callbacks deferred until bo is inactive: */
	struct list_head fence_cbs;

	/* crtcs pending async atomic updates: */
	uint32_t pending_crtcs;
	wait_queue_head_t pending_crtcs_event;
@@ -194,8 +189,6 @@ int msm_gem_prime_pin(struct drm_gem_object *obj);
void msm_gem_prime_unpin(struct drm_gem_object *obj);
void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
void *msm_gem_vaddr(struct drm_gem_object *obj);
int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
		struct msm_fence_cb *cb);
void msm_gem_move_to_active(struct drm_gem_object *obj,
		struct msm_gpu *gpu, bool write, uint32_t fence);
void msm_gem_move_to_inactive(struct drm_gem_object *obj);
+53 −34
Original line number Diff line number Diff line
@@ -15,49 +15,68 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/fence.h>

#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_fence_context *
msm_fence_context_alloc(struct drm_device *dev, const char *name)
{
	struct msm_fence_context *fctx;

	fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
	if (!fctx)
		return ERR_PTR(-ENOMEM);

	fctx->dev = dev;
	fctx->name = name;
	init_waitqueue_head(&fctx->event);
	INIT_LIST_HEAD(&fctx->fence_cbs);

	return fctx;
}

void msm_fence_context_free(struct msm_fence_context *fctx)
{
	kfree(fctx);
}

static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence)
{
	struct msm_drm_private *priv = dev->dev_private;
	return (int32_t)(priv->completed_fence - fence) >= 0;
	return (int32_t)(fctx->completed_fence - fence) >= 0;
}

int msm_wait_fence(struct drm_device *dev, uint32_t fence,
int msm_wait_fence(struct msm_fence_context *fctx, 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);
	if (fence > fctx->last_fence) {
		DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n",
				fctx->name, fence, fctx->last_fence);
		return -EINVAL;
	}

	if (!timeout) {
		/* no-wait: */
		ret = fence_completed(dev, fence) ? 0 : -EBUSY;
		ret = fence_completed(fctx, fence) ? 0 : -EBUSY;
	} else {
		unsigned long remaining_jiffies = timeout_to_jiffies(timeout);

		if (interruptible)
			ret = wait_event_interruptible_timeout(priv->fence_event,
				fence_completed(dev, fence),
			ret = wait_event_interruptible_timeout(fctx->event,
				fence_completed(fctx, fence),
				remaining_jiffies);
		else
			ret = wait_event_timeout(priv->fence_event,
				fence_completed(dev, fence),
			ret = wait_event_timeout(fctx->event,
				fence_completed(fctx, fence),
				remaining_jiffies);

		if (ret == 0) {
			DBG("timeout waiting for fence: %u (completed: %u)",
					fence, priv->completed_fence);
					fence, fctx->completed_fence);
			ret = -ETIMEDOUT;
		} else if (ret != -ERESTARTSYS) {
			ret = 0;
@@ -67,50 +86,50 @@ int msm_wait_fence(struct drm_device *dev, uint32_t fence,
	return ret;
}

int msm_queue_fence_cb(struct drm_device *dev,
int msm_queue_fence_cb(struct msm_fence_context *fctx,
		struct msm_fence_cb *cb, uint32_t fence)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct msm_drm_private *priv = fctx->dev->dev_private;
	int ret = 0;

	mutex_lock(&dev->struct_mutex);
	mutex_lock(&fctx->dev->struct_mutex);
	if (!list_empty(&cb->work.entry)) {
		ret = -EINVAL;
	} else if (fence > priv->completed_fence) {
	} else if (fence > fctx->completed_fence) {
		cb->fence = fence;
		list_add_tail(&cb->work.entry, &priv->fence_cbs);
		list_add_tail(&cb->work.entry, &fctx->fence_cbs);
	} else {
		queue_work(priv->wq, &cb->work);
	}
	mutex_unlock(&dev->struct_mutex);
	mutex_unlock(&fctx->dev->struct_mutex);

	return ret;
}

/* called from workqueue */
void msm_update_fence(struct drm_device *dev, uint32_t fence)
void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
{
	struct msm_drm_private *priv = dev->dev_private;
	struct msm_drm_private *priv = fctx->dev->dev_private;

	mutex_lock(&dev->struct_mutex);
	priv->completed_fence = max(fence, priv->completed_fence);
	mutex_lock(&fctx->dev->struct_mutex);
	fctx->completed_fence = max(fence, fctx->completed_fence);

	while (!list_empty(&priv->fence_cbs)) {
	while (!list_empty(&fctx->fence_cbs)) {
		struct msm_fence_cb *cb;

		cb = list_first_entry(&priv->fence_cbs,
		cb = list_first_entry(&fctx->fence_cbs,
				struct msm_fence_cb, work.entry);

		if (cb->fence > priv->completed_fence)
		if (cb->fence > fctx->completed_fence)
			break;

		list_del_init(&cb->work.entry);
		queue_work(priv->wq, &cb->work);
	}

	mutex_unlock(&dev->struct_mutex);
	mutex_unlock(&fctx->dev->struct_mutex);

	wake_up_all(&priv->fence_event);
	wake_up_all(&fctx->event);
}

void __msm_fence_worker(struct work_struct *work)
Loading