OSDN Git Service

drm/msm/gpu: use pm-runtime
authorRob Clark <robdclark@gmail.com>
Fri, 10 Feb 2017 20:36:33 +0000 (15:36 -0500)
committerRob Clark <robdclark@gmail.com>
Sat, 8 Apr 2017 10:59:31 +0000 (06:59 -0400)
We need to use pm-runtime properly when IOMMU is using device_link() to
control it's own clocks.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/msm_debugfs.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h

index ece39b1..bc170b7 100644 (file)
@@ -155,21 +155,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
 
        if (gpu) {
                int ret;
-               mutex_lock(&dev->struct_mutex);
-               gpu->funcs->pm_resume(gpu);
-               mutex_unlock(&dev->struct_mutex);
 
-               disable_irq(gpu->irq);
-
-               ret = gpu->funcs->hw_init(gpu);
+               pm_runtime_get_sync(&pdev->dev);
+               ret = msm_gpu_hw_init(gpu);
+               pm_runtime_put_sync(&pdev->dev);
                if (ret) {
                        dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
                        gpu->funcs->destroy(gpu);
                        gpu = NULL;
-               } else {
-                       enable_irq(gpu->irq);
-                       /* give inactive pm a chance to kick in: */
-                       msm_gpu_retire(gpu);
                }
        }
 
@@ -296,12 +289,35 @@ static const struct of_device_id dt_match[] = {
        {}
 };
 
+#ifdef CONFIG_PM
+static int adreno_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct msm_gpu *gpu = platform_get_drvdata(pdev);
+
+       return gpu->funcs->pm_resume(gpu);
+}
+
+static int adreno_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct msm_gpu *gpu = platform_get_drvdata(pdev);
+
+       return gpu->funcs->pm_suspend(gpu);
+}
+#endif
+
+static const struct dev_pm_ops adreno_pm_ops = {
+       SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL)
+};
+
 static struct platform_driver adreno_driver = {
        .probe = adreno_probe,
        .remove = adreno_remove,
        .driver = {
                .name = "adreno",
                .of_match_table = dt_match,
+               .pm = &adreno_pm_ops,
        },
 };
 
index 50e0f54..823f9df 100644 (file)
@@ -115,6 +115,9 @@ void adreno_recover(struct msm_gpu *gpu)
        struct drm_device *dev = gpu->dev;
        int ret;
 
+       // XXX pm-runtime??  we *need* the device to be off after this
+       // so maybe continuing to call ->pm_suspend/resume() is better?
+
        gpu->funcs->pm_suspend(gpu);
 
        /* reset ringbuffer: */
@@ -127,13 +130,11 @@ void adreno_recover(struct msm_gpu *gpu)
 
        gpu->funcs->pm_resume(gpu);
 
-       disable_irq(gpu->irq);
-       ret = gpu->funcs->hw_init(gpu);
+       ret = msm_gpu_hw_init(gpu);
        if (ret) {
                dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
                /* hmm, oh well? */
        }
-       enable_irq(gpu->irq);
 }
 
 void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
@@ -365,6 +366,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        if (ret)
                return ret;
 
+       pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
        if (ret) {
                dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
index 89b3b79..1855182 100644 (file)
@@ -28,9 +28,9 @@ static int msm_gpu_show(struct drm_device *dev, struct seq_file *m)
 
        if (gpu) {
                seq_printf(m, "%s Status:\n", gpu->name);
-               gpu->funcs->pm_resume(gpu);
+               pm_runtime_get_sync(&gpu->pdev->dev);
                gpu->funcs->show(gpu, m);
-               gpu->funcs->pm_suspend(gpu);
+               pm_runtime_put_sync(&gpu->pdev->dev);
        }
 
        return 0;
index 9208e67..5875aa8 100644 (file)
@@ -265,6 +265,8 @@ static int msm_drm_uninit(struct device *dev)
 
        if (gpu) {
                mutex_lock(&ddev->struct_mutex);
+               // XXX what do we do here?
+               //pm_runtime_enable(&pdev->dev);
                gpu->funcs->pm_suspend(gpu);
                mutex_unlock(&ddev->struct_mutex);
                gpu->funcs->destroy(gpu);
index 99e05aa..41d2abc 100644 (file)
@@ -152,18 +152,9 @@ static int disable_axi(struct msm_gpu *gpu)
 
 int msm_gpu_pm_resume(struct msm_gpu *gpu)
 {
-       struct drm_device *dev = gpu->dev;
        int ret;
 
-       DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       if (gpu->active_cnt++ > 0)
-               return 0;
-
-       if (WARN_ON(gpu->active_cnt <= 0))
-               return -EINVAL;
+       DBG("%s", gpu->name);
 
        ret = enable_pwrrail(gpu);
        if (ret)
@@ -177,23 +168,16 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
        if (ret)
                return ret;
 
+       gpu->needs_hw_init = true;
+
        return 0;
 }
 
 int msm_gpu_pm_suspend(struct msm_gpu *gpu)
 {
-       struct drm_device *dev = gpu->dev;
        int ret;
 
-       DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       if (--gpu->active_cnt > 0)
-               return 0;
-
-       if (WARN_ON(gpu->active_cnt < 0))
-               return -EINVAL;
+       DBG("%s", gpu->name);
 
        ret = disable_axi(gpu);
        if (ret)
@@ -210,53 +194,20 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
        return 0;
 }
 
-/*
- * Inactivity detection (for suspend):
- */
-
-static void inactive_worker(struct work_struct *work)
-{
-       struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work);
-       struct drm_device *dev = gpu->dev;
-
-       if (gpu->inactive)
-               return;
-
-       DBG("%s: inactive!\n", gpu->name);
-       mutex_lock(&dev->struct_mutex);
-       if (!(msm_gpu_active(gpu) || gpu->inactive)) {
-               disable_axi(gpu);
-               disable_clk(gpu);
-               gpu->inactive = true;
-       }
-       mutex_unlock(&dev->struct_mutex);
-}
-
-static void inactive_handler(unsigned long data)
+int msm_gpu_hw_init(struct msm_gpu *gpu)
 {
-       struct msm_gpu *gpu = (struct msm_gpu *)data;
-       struct msm_drm_private *priv = gpu->dev->dev_private;
+       int ret;
 
-       queue_work(priv->wq, &gpu->inactive_work);
-}
+       if (!gpu->needs_hw_init)
+               return 0;
 
-/* cancel inactive timer and make sure we are awake: */
-static void inactive_cancel(struct msm_gpu *gpu)
-{
-       DBG("%s", gpu->name);
-       del_timer(&gpu->inactive_timer);
-       if (gpu->inactive) {
-               enable_clk(gpu);
-               enable_axi(gpu);
-               gpu->inactive = false;
-       }
-}
+       disable_irq(gpu->irq);
+       ret = gpu->funcs->hw_init(gpu);
+       if (!ret)
+               gpu->needs_hw_init = false;
+       enable_irq(gpu->irq);
 
-static void inactive_start(struct msm_gpu *gpu)
-{
-       DBG("%s", gpu->name);
-       mod_timer(&gpu->inactive_timer,
-                       round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES));
+       return ret;
 }
 
 /*
@@ -296,8 +247,9 @@ static void recover_worker(struct work_struct *work)
                /* retire completed submits, plus the one that hung: */
                retire_submits(gpu);
 
-               inactive_cancel(gpu);
+               pm_runtime_get_sync(&gpu->pdev->dev);
                gpu->funcs->recover(gpu);
+               pm_runtime_put_sync(&gpu->pdev->dev);
 
                /* replay the remaining submits after the one that hung: */
                list_for_each_entry(submit, &gpu->submit_list, node) {
@@ -400,6 +352,8 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
 {
        unsigned long flags;
 
+       pm_runtime_get_sync(&gpu->pdev->dev);
+
        spin_lock_irqsave(&gpu->perf_lock, flags);
        /* we could dynamically enable/disable perfcntr registers too.. */
        gpu->last_sample.active = msm_gpu_active(gpu);
@@ -413,6 +367,7 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
 void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
 {
        gpu->perfcntr_active = false;
+       pm_runtime_put_sync(&gpu->pdev->dev);
 }
 
 /* returns -errno or # of cntrs sampled */
@@ -458,6 +413,8 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
                drm_gem_object_unreference(&msm_obj->base);
        }
 
+       pm_runtime_mark_last_busy(&gpu->pdev->dev);
+       pm_runtime_put_autosuspend(&gpu->pdev->dev);
        msm_gem_submit_free(submit);
 }
 
@@ -492,9 +449,6 @@ static void retire_worker(struct work_struct *work)
        mutex_lock(&dev->struct_mutex);
        retire_submits(gpu);
        mutex_unlock(&dev->struct_mutex);
-
-       if (!msm_gpu_active(gpu))
-               inactive_start(gpu);
 }
 
 /* call from irq handler to schedule work to retire bo's */
@@ -515,7 +469,9 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       inactive_cancel(gpu);
+       pm_runtime_get_sync(&gpu->pdev->dev);
+
+       msm_gpu_hw_init(gpu);
 
        list_add_tail(&submit->node, &gpu->submit_list);
 
@@ -576,7 +532,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        gpu->dev = drm;
        gpu->funcs = funcs;
        gpu->name = name;
-       gpu->inactive = true;
        gpu->fctx = msm_fence_context_alloc(drm, name);
        if (IS_ERR(gpu->fctx)) {
                ret = PTR_ERR(gpu->fctx);
@@ -586,13 +541,10 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 
        INIT_LIST_HEAD(&gpu->active_list);
        INIT_WORK(&gpu->retire_work, retire_worker);
-       INIT_WORK(&gpu->inactive_work, inactive_worker);
        INIT_WORK(&gpu->recover_work, recover_worker);
 
        INIT_LIST_HEAD(&gpu->submit_list);
 
-       setup_timer(&gpu->inactive_timer, inactive_handler,
-                       (unsigned long)gpu);
        setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
                        (unsigned long)gpu);
 
@@ -684,6 +636,9 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                goto fail;
        }
 
+       gpu->pdev = pdev;
+       platform_set_drvdata(pdev, gpu);
+
        bs_init(gpu);
 
        return 0;
index c4c39d3..72dba97 100644 (file)
@@ -64,6 +64,7 @@ struct msm_gpu_funcs {
 struct msm_gpu {
        const char *name;
        struct drm_device *dev;
+       struct platform_device *pdev;
        const struct msm_gpu_funcs *funcs;
 
        /* performance counters (hw & sw): */
@@ -88,9 +89,8 @@ struct msm_gpu {
        /* fencing: */
        struct msm_fence_context *fctx;
 
-       /* is gpu powered/active? */
-       int active_cnt;
-       bool inactive;
+       /* does gpu need hw_init? */
+       bool needs_hw_init;
 
        /* worker for handling active-list retiring: */
        struct work_struct retire_work;
@@ -114,9 +114,7 @@ struct msm_gpu {
        /* Hang and Inactivity Detection:
         */
 #define DRM_MSM_INACTIVE_PERIOD   66 /* in ms (roughly four frames) */
-#define DRM_MSM_INACTIVE_JIFFIES  msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD)
-       struct timer_list inactive_timer;
-       struct work_struct inactive_work;
+
 #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
 #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
        struct timer_list hangcheck_timer;
@@ -196,6 +194,8 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
 int msm_gpu_pm_suspend(struct msm_gpu *gpu);
 int msm_gpu_pm_resume(struct msm_gpu *gpu);
 
+int msm_gpu_hw_init(struct msm_gpu *gpu);
+
 void msm_gpu_perfcntr_start(struct msm_gpu *gpu);
 void msm_gpu_perfcntr_stop(struct msm_gpu *gpu);
 int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,