summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2016-03-17 19:17:16 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2016-08-08 11:03:33 +0100
commitb20b8d4bc709977bf6c66fd08f3539535eaaf182 (patch)
tree21a3d5be7fca43a5385d496c21cab47ce1f7a3e0
parenta09a4e88711b1a8bb8cb1bb825cb85a1941795c2 (diff)
drm: etnaviv: try harder to reset the GPU at probe timedrm-etnaviv-devel
Try harder to reset the GPU at probe time by allowing the GPU to enter runtime PM even if it indicates that it is busy. Where platforms implement PM domains, this allows the GPU domain to be power cycled, which can recover a hung GPU. This can't be done in normal operation as we need to drop the mutex, and dropping the mutex will permit GPU submissions which will keep the GPU from idling. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c22
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h1
2 files changed, 21 insertions, 2 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 8948ab07ff36..57aa177ac348 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -599,7 +599,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
{
- int ret, i;
+ int ret, i, try;
struct iommu_domain *iommu;
enum etnaviv_iommu_version version;
bool mmuv2;
@@ -642,7 +642,20 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
gpu->memory_base = dma_mask - SZ_2G + 1;
}
- ret = etnaviv_hw_reset(gpu);
+ for (try = 0; try < 2; try++) {
+ ret = etnaviv_hw_reset(gpu);
+ if (ret == 0)
+ break;
+
+ dev_warn(gpu->dev, "GPU failed to reset, trying to power cycle\n");
+ gpu->force_rpm_idle = true;
+ pm_runtime_put_sync(gpu->dev);
+ msleep(100);
+ ret = pm_runtime_get_sync(gpu->dev);
+ gpu->force_rpm_idle = false;
+ if (ret)
+ break;
+ }
if (ret)
goto fail;
@@ -1798,6 +1811,11 @@ static int __maybe_unused etnaviv_gpu_rpm_suspend(struct device *dev)
{
struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+ if (gpu->force_rpm_idle) {
+ etnaviv_gpu_clk_disable(gpu);
+ return 0;
+ }
+
/* If we have outstanding fences, we're not idle */
if (gpu->completed_fence != gpu->active_fence)
return -EBUSY;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 1332802aa831..f36c75ed3470 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -101,6 +101,7 @@ struct etnaviv_gpu {
struct mutex lock;
struct etnaviv_chip_identity identity;
struct etnaviv_file_private *lastctx;
+ bool force_rpm_idle;
bool switch_context;
/* 'ring'-buffer: */