diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_fence.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_fence.c | 86 | 
1 files changed, 83 insertions, 3 deletions
diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 56641408ea74..96599ec3eb78 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -8,6 +8,35 @@  #include "msm_drv.h"  #include "msm_fence.h" +#include "msm_gpu.h" + +static struct msm_gpu *fctx2gpu(struct msm_fence_context *fctx) +{ +	struct msm_drm_private *priv = fctx->dev->dev_private; +	return priv->gpu; +} + +static enum hrtimer_restart deadline_timer(struct hrtimer *t) +{ +	struct msm_fence_context *fctx = container_of(t, +			struct msm_fence_context, deadline_timer); + +	kthread_queue_work(fctx2gpu(fctx)->worker, &fctx->deadline_work); + +	return HRTIMER_NORESTART; +} + +static void deadline_work(struct kthread_work *work) +{ +	struct msm_fence_context *fctx = container_of(work, +			struct msm_fence_context, deadline_work); + +	/* If deadline fence has already passed, nothing to do: */ +	if (msm_fence_completed(fctx, fctx->next_deadline_fence)) +		return; + +	msm_devfreq_boost(fctx2gpu(fctx), 2); +}  struct msm_fence_context * @@ -36,6 +65,13 @@ msm_fence_context_alloc(struct drm_device *dev, volatile uint32_t *fenceptr,  	fctx->completed_fence = fctx->last_fence;  	*fctx->fenceptr = fctx->last_fence; +	hrtimer_init(&fctx->deadline_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); +	fctx->deadline_timer.function = deadline_timer; + +	kthread_init_work(&fctx->deadline_work, deadline_work); + +	fctx->next_deadline = ktime_get(); +  	return fctx;  } @@ -62,6 +98,8 @@ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)  	spin_lock_irqsave(&fctx->spinlock, flags);  	if (fence_after(fence, fctx->completed_fence))  		fctx->completed_fence = fence; +	if (msm_fence_completed(fctx, fctx->next_deadline_fence)) +		hrtimer_cancel(&fctx->deadline_timer);  	spin_unlock_irqrestore(&fctx->spinlock, flags);  } @@ -92,14 +130,50 @@ static bool msm_fence_signaled(struct dma_fence *fence)  	return msm_fence_completed(f->fctx, f->base.seqno);  } +static void msm_fence_set_deadline(struct dma_fence *fence, ktime_t deadline) +{ +	struct msm_fence *f = to_msm_fence(fence); +	struct msm_fence_context *fctx = f->fctx; +	unsigned long flags; +	ktime_t now; + +	spin_lock_irqsave(&fctx->spinlock, flags); +	now = ktime_get(); + +	if (ktime_after(now, fctx->next_deadline) || +			ktime_before(deadline, fctx->next_deadline)) { +		fctx->next_deadline = deadline; +		fctx->next_deadline_fence = +			max(fctx->next_deadline_fence, (uint32_t)fence->seqno); + +		/* +		 * Set timer to trigger boost 3ms before deadline, or +		 * if we are already less than 3ms before the deadline +		 * schedule boost work immediately. +		 */ +		deadline = ktime_sub(deadline, ms_to_ktime(3)); + +		if (ktime_after(now, deadline)) { +			kthread_queue_work(fctx2gpu(fctx)->worker, +					&fctx->deadline_work); +		} else { +			hrtimer_start(&fctx->deadline_timer, deadline, +					HRTIMER_MODE_ABS); +		} +	} + +	spin_unlock_irqrestore(&fctx->spinlock, flags); +} +  static const struct dma_fence_ops msm_fence_ops = {  	.get_driver_name = msm_fence_get_driver_name,  	.get_timeline_name = msm_fence_get_timeline_name,  	.signaled = msm_fence_signaled, +	.set_deadline = msm_fence_set_deadline,  };  struct dma_fence * -msm_fence_alloc(struct msm_fence_context *fctx) +msm_fence_alloc(void)  {  	struct msm_fence *f; @@ -107,10 +181,16 @@ msm_fence_alloc(struct msm_fence_context *fctx)  	if (!f)  		return ERR_PTR(-ENOMEM); +	return &f->base; +} + +void +msm_fence_init(struct dma_fence *fence, struct msm_fence_context *fctx) +{ +	struct msm_fence *f = to_msm_fence(fence); +  	f->fctx = fctx;  	dma_fence_init(&f->base, &msm_fence_ops, &fctx->spinlock,  		       fctx->context, ++fctx->last_fence); - -	return &f->base;  }  |