diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gpu.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 220 | 
1 files changed, 50 insertions, 170 deletions
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 0ebf7bc6ad09..8a3a592da3a4 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -13,8 +13,6 @@  #include <generated/utsrelease.h>  #include <linux/string_helpers.h> -#include <linux/devfreq.h> -#include <linux/devfreq_cooling.h>  #include <linux/devcoredump.h>  #include <linux/sched/task.h> @@ -22,106 +20,6 @@   * Power Management:   */ -static int msm_devfreq_target(struct device *dev, unsigned long *freq, -		u32 flags) -{ -	struct msm_gpu *gpu = dev_to_gpu(dev); -	struct dev_pm_opp *opp; - -	opp = devfreq_recommended_opp(dev, freq, flags); - -	if (IS_ERR(opp)) -		return PTR_ERR(opp); - -	trace_msm_gpu_freq_change(dev_pm_opp_get_freq(opp)); - -	if (gpu->funcs->gpu_set_freq) -		gpu->funcs->gpu_set_freq(gpu, opp); -	else -		clk_set_rate(gpu->core_clk, *freq); - -	dev_pm_opp_put(opp); - -	return 0; -} - -static int msm_devfreq_get_dev_status(struct device *dev, -		struct devfreq_dev_status *status) -{ -	struct msm_gpu *gpu = dev_to_gpu(dev); -	ktime_t time; - -	if (gpu->funcs->gpu_get_freq) -		status->current_frequency = gpu->funcs->gpu_get_freq(gpu); -	else -		status->current_frequency = clk_get_rate(gpu->core_clk); - -	status->busy_time = gpu->funcs->gpu_busy(gpu); - -	time = ktime_get(); -	status->total_time = ktime_us_delta(time, gpu->devfreq.time); -	gpu->devfreq.time = time; - -	return 0; -} - -static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) -{ -	struct msm_gpu *gpu = dev_to_gpu(dev); - -	if (gpu->funcs->gpu_get_freq) -		*freq = gpu->funcs->gpu_get_freq(gpu); -	else -		*freq = clk_get_rate(gpu->core_clk); - -	return 0; -} - -static struct devfreq_dev_profile msm_devfreq_profile = { -	.polling_ms = 10, -	.target = msm_devfreq_target, -	.get_dev_status = msm_devfreq_get_dev_status, -	.get_cur_freq = msm_devfreq_get_cur_freq, -}; - -static void msm_devfreq_init(struct msm_gpu *gpu) -{ -	/* We need target support to do devfreq */ -	if (!gpu->funcs->gpu_busy) -		return; - -	msm_devfreq_profile.initial_freq = gpu->fast_rate; - -	/* -	 * Don't set the freq_table or max_state and let devfreq build the table -	 * from OPP -	 * After a deferred probe, these may have be left to non-zero values, -	 * so set them back to zero before creating the devfreq device -	 */ -	msm_devfreq_profile.freq_table = NULL; -	msm_devfreq_profile.max_state = 0; - -	gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev, -			&msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, -			NULL); - -	if (IS_ERR(gpu->devfreq.devfreq)) { -		DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); -		gpu->devfreq.devfreq = NULL; -		return; -	} - -	devfreq_suspend_device(gpu->devfreq.devfreq); - -	gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node, -			gpu->devfreq.devfreq); -	if (IS_ERR(gpu->cooling)) { -		DRM_DEV_ERROR(&gpu->pdev->dev, -				"Couldn't register GPU cooling device\n"); -		gpu->cooling = NULL; -	} -} -  static int enable_pwrrail(struct msm_gpu *gpu)  {  	struct drm_device *dev = gpu->dev; @@ -196,14 +94,6 @@ static int disable_axi(struct msm_gpu *gpu)  	return 0;  } -void msm_gpu_resume_devfreq(struct msm_gpu *gpu) -{ -	gpu->devfreq.busy_cycles = 0; -	gpu->devfreq.time = ktime_get(); - -	devfreq_resume_device(gpu->devfreq.devfreq); -} -  int msm_gpu_pm_resume(struct msm_gpu *gpu)  {  	int ret; @@ -223,7 +113,7 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)  	if (ret)  		return ret; -	msm_gpu_resume_devfreq(gpu); +	msm_devfreq_resume(gpu);  	gpu->needs_hw_init = true; @@ -237,7 +127,7 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)  	DBG("%s", gpu->name);  	trace_msm_gpu_suspend(0); -	devfreq_suspend_device(gpu->devfreq.devfreq); +	msm_devfreq_suspend(gpu);  	ret = disable_axi(gpu);  	if (ret) @@ -278,16 +168,18 @@ static void update_fences(struct msm_gpu *gpu, struct msm_ringbuffer *ring,  		uint32_t fence)  {  	struct msm_gem_submit *submit; +	unsigned long flags; -	spin_lock(&ring->submit_lock); +	spin_lock_irqsave(&ring->submit_lock, flags);  	list_for_each_entry(submit, &ring->submits, node) {  		if (submit->seqno > fence)  			break;  		msm_update_fence(submit->ring->fctx, -			submit->fence->seqno); +			submit->hw_fence->seqno); +		dma_fence_signal(submit->hw_fence);  	} -	spin_unlock(&ring->submit_lock); +	spin_unlock_irqrestore(&ring->submit_lock, flags);  }  #ifdef CONFIG_DEV_COREDUMP @@ -443,15 +335,16 @@ static struct msm_gem_submit *  find_submit(struct msm_ringbuffer *ring, uint32_t fence)  {  	struct msm_gem_submit *submit; +	unsigned long flags; -	spin_lock(&ring->submit_lock); +	spin_lock_irqsave(&ring->submit_lock, flags);  	list_for_each_entry(submit, &ring->submits, node) {  		if (submit->seqno == fence) { -			spin_unlock(&ring->submit_lock); +			spin_unlock_irqrestore(&ring->submit_lock, flags);  			return submit;  		}  	} -	spin_unlock(&ring->submit_lock); +	spin_unlock_irqrestore(&ring->submit_lock, flags);  	return NULL;  } @@ -487,10 +380,6 @@ static void recover_worker(struct kthread_work *work)  			put_task_struct(task);  		} -		/* msm_rd_dump_submit() needs bo locked to dump: */ -		for (i = 0; i < submit->nr_bos; i++) -			msm_gem_lock(&submit->bos[i].obj->base); -  		if (comm && cmd) {  			DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n",  				gpu->name, comm, cmd); @@ -500,9 +389,6 @@ static void recover_worker(struct kthread_work *work)  		} else {  			msm_rd_dump_submit(priv->hangrd, submit, NULL);  		} - -		for (i = 0; i < submit->nr_bos; i++) -			msm_gem_unlock(&submit->bos[i].obj->base);  	}  	/* Record the crash state */ @@ -547,11 +433,12 @@ static void recover_worker(struct kthread_work *work)  		 */  		for (i = 0; i < gpu->nr_rings; i++) {  			struct msm_ringbuffer *ring = gpu->rb[i]; +			unsigned long flags; -			spin_lock(&ring->submit_lock); +			spin_lock_irqsave(&ring->submit_lock, flags);  			list_for_each_entry(submit, &ring->submits, node)  				gpu->funcs->submit(gpu, submit); -			spin_unlock(&ring->submit_lock); +			spin_unlock_irqrestore(&ring->submit_lock, flags);  		}  	} @@ -641,7 +528,7 @@ static void hangcheck_handler(struct timer_list *t)  		hangcheck_timer_reset(gpu);  	/* workaround for missing irq: */ -	kthread_queue_work(gpu->worker, &gpu->retire_work); +	msm_gpu_retire(gpu);  }  /* @@ -752,7 +639,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,  	int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT;  	volatile struct msm_gpu_submit_stats *stats;  	u64 elapsed, clock = 0; -	int i; +	unsigned long flags;  	stats = &ring->memptrs->stats[index];  	/* Convert 19.2Mhz alwayson ticks to nanoseconds for elapsed time */ @@ -768,22 +655,22 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_ringbuffer *ring,  	trace_msm_gpu_submit_retired(submit, elapsed, clock,  		stats->alwayson_start, stats->alwayson_end); -	for (i = 0; i < submit->nr_bos; i++) { -		struct drm_gem_object *obj = &submit->bos[i].obj->base; - -		msm_gem_lock(obj); -		msm_gem_active_put(obj); -		msm_gem_unpin_iova_locked(obj, submit->aspace); -		msm_gem_unlock(obj); -		drm_gem_object_put(obj); -	} +	msm_submit_retire(submit);  	pm_runtime_mark_last_busy(&gpu->pdev->dev);  	pm_runtime_put_autosuspend(&gpu->pdev->dev); -	spin_lock(&ring->submit_lock); +	spin_lock_irqsave(&ring->submit_lock, flags);  	list_del(&submit->node); -	spin_unlock(&ring->submit_lock); +	spin_unlock_irqrestore(&ring->submit_lock, flags); + +	/* Update devfreq on transition from active->idle: */ +	mutex_lock(&gpu->active_lock); +	gpu->active_submits--; +	WARN_ON(gpu->active_submits < 0); +	if (!gpu->active_submits) +		msm_devfreq_idle(gpu); +	mutex_unlock(&gpu->active_lock);  	msm_gem_submit_put(submit);  } @@ -798,18 +685,19 @@ static void retire_submits(struct msm_gpu *gpu)  		while (true) {  			struct msm_gem_submit *submit = NULL; +			unsigned long flags; -			spin_lock(&ring->submit_lock); +			spin_lock_irqsave(&ring->submit_lock, flags);  			submit = list_first_entry_or_null(&ring->submits,  					struct msm_gem_submit, node); -			spin_unlock(&ring->submit_lock); +			spin_unlock_irqrestore(&ring->submit_lock, flags);  			/*  			 * If no submit, we are done.  If submit->fence hasn't  			 * been signalled, then later submits are not signalled  			 * either, so we are also done.  			 */ -			if (submit && dma_fence_is_signaled(submit->fence)) { +			if (submit && dma_fence_is_signaled(submit->hw_fence)) {  				retire_submit(gpu, ring, submit);  			} else {  				break; @@ -821,10 +709,6 @@ static void retire_submits(struct msm_gpu *gpu)  static void retire_worker(struct kthread_work *work)  {  	struct msm_gpu *gpu = container_of(work, struct msm_gpu, retire_work); -	int i; - -	for (i = 0; i < gpu->nr_rings; i++) -		update_fences(gpu, gpu->rb[i], gpu->rb[i]->memptrs->fence);  	retire_submits(gpu);  } @@ -832,6 +716,11 @@ static void retire_worker(struct kthread_work *work)  /* call from irq handler to schedule work to retire bo's */  void msm_gpu_retire(struct msm_gpu *gpu)  { +	int i; + +	for (i = 0; i < gpu->nr_rings; i++) +		update_fences(gpu, gpu->rb[i], gpu->rb[i]->memptrs->fence); +  	kthread_queue_work(gpu->worker, &gpu->retire_work);  	update_sw_cntrs(gpu);  } @@ -842,7 +731,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)  	struct drm_device *dev = gpu->dev;  	struct msm_drm_private *priv = dev->dev_private;  	struct msm_ringbuffer *ring = submit->ring; -	int i; +	unsigned long flags;  	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -856,32 +745,22 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)  	update_sw_cntrs(gpu); -	for (i = 0; i < submit->nr_bos; i++) { -		struct msm_gem_object *msm_obj = submit->bos[i].obj; -		struct drm_gem_object *drm_obj = &msm_obj->base; -		uint64_t iova; - -		/* submit takes a reference to the bo and iova until retired: */ -		drm_gem_object_get(&msm_obj->base); -		msm_gem_get_and_pin_iova_locked(&msm_obj->base, submit->aspace, &iova); - -		if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) -			dma_resv_add_excl_fence(drm_obj->resv, submit->fence); -		else if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) -			dma_resv_add_shared_fence(drm_obj->resv, submit->fence); - -		msm_gem_active_get(drm_obj, gpu); -	} -  	/*  	 * ring->submits holds a ref to the submit, to deal with the case  	 * that a submit completes before msm_ioctl_gem_submit() returns.  	 */  	msm_gem_submit_get(submit); -	spin_lock(&ring->submit_lock); +	spin_lock_irqsave(&ring->submit_lock, flags);  	list_add_tail(&submit->node, &ring->submits); -	spin_unlock(&ring->submit_lock); +	spin_unlock_irqrestore(&ring->submit_lock, flags); + +	/* Update devfreq on transition from idle->active: */ +	mutex_lock(&gpu->active_lock); +	if (!gpu->active_submits) +		msm_devfreq_active(gpu); +	gpu->active_submits++; +	mutex_unlock(&gpu->active_lock);  	gpu->funcs->submit(gpu, submit);  	priv->lastctx = submit->queue->ctx; @@ -968,6 +847,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,  	sched_set_fifo_low(gpu->worker->task);  	INIT_LIST_HEAD(&gpu->active_list); +	mutex_init(&gpu->active_lock);  	kthread_init_work(&gpu->retire_work, retire_worker);  	kthread_init_work(&gpu->recover_work, recover_worker);  	kthread_init_work(&gpu->fault_work, fault_worker); @@ -1078,7 +958,7 @@ fail:  		gpu->rb[i] = NULL;  	} -	msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace, false); +	msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace);  	platform_set_drvdata(pdev, NULL);  	return ret; @@ -1097,7 +977,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)  		gpu->rb[i] = NULL;  	} -	msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace, false); +	msm_gem_kernel_put(gpu->memptrs_bo, gpu->aspace);  	if (!IS_ERR_OR_NULL(gpu->aspace)) {  		gpu->aspace->mmu->funcs->detach(gpu->aspace->mmu); @@ -1108,5 +988,5 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)  		kthread_destroy_worker(gpu->worker);  	} -	devfreq_cooling_unregister(gpu->cooling); +	msm_devfreq_cleanup(gpu);  }  | 
