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); } |