Commit c4a8d475 authored by Jordan Crouse's avatar Jordan Crouse Committed by Rob Clark

drm/msm: gpu: Return error on hw_init failure

When the GPU hardware init function fails (like say, ME_INIT timed
out) return error instead of blindly continuing on. This gives us
a small chance of saving the system before it goes boom.
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent bcc188b7
...@@ -41,7 +41,7 @@ extern bool hang_debug; ...@@ -41,7 +41,7 @@ extern bool hang_debug;
static void a3xx_dump(struct msm_gpu *gpu); static void a3xx_dump(struct msm_gpu *gpu);
static void a3xx_me_init(struct msm_gpu *gpu) static bool a3xx_me_init(struct msm_gpu *gpu)
{ {
struct msm_ringbuffer *ring = gpu->rb; struct msm_ringbuffer *ring = gpu->rb;
...@@ -65,7 +65,7 @@ static void a3xx_me_init(struct msm_gpu *gpu) ...@@ -65,7 +65,7 @@ static void a3xx_me_init(struct msm_gpu *gpu)
OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000);
gpu->funcs->flush(gpu); gpu->funcs->flush(gpu);
gpu->funcs->idle(gpu); return gpu->funcs->idle(gpu);
} }
static int a3xx_hw_init(struct msm_gpu *gpu) static int a3xx_hw_init(struct msm_gpu *gpu)
...@@ -294,9 +294,7 @@ static int a3xx_hw_init(struct msm_gpu *gpu) ...@@ -294,9 +294,7 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
/* clear ME_HALT to start micro engine */ /* clear ME_HALT to start micro engine */
gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
a3xx_me_init(gpu); return a3xx_me_init(gpu) ? 0 : -EINVAL;
return 0;
} }
static void a3xx_recover(struct msm_gpu *gpu) static void a3xx_recover(struct msm_gpu *gpu)
...@@ -337,17 +335,22 @@ static void a3xx_destroy(struct msm_gpu *gpu) ...@@ -337,17 +335,22 @@ static void a3xx_destroy(struct msm_gpu *gpu)
kfree(a3xx_gpu); kfree(a3xx_gpu);
} }
static void a3xx_idle(struct msm_gpu *gpu) static bool a3xx_idle(struct msm_gpu *gpu)
{ {
/* wait for ringbuffer to drain: */ /* wait for ringbuffer to drain: */
adreno_idle(gpu); if (!adreno_idle(gpu))
return false;
/* then wait for GPU to finish: */ /* then wait for GPU to finish: */
if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
A3XX_RBBM_STATUS_GPU_BUSY))) A3XX_RBBM_STATUS_GPU_BUSY))) {
DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
/* TODO maybe we need to reset GPU here to recover from hang? */ /* TODO maybe we need to reset GPU here to recover from hang? */
return false;
}
return true;
} }
static irqreturn_t a3xx_irq(struct msm_gpu *gpu) static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
......
...@@ -113,7 +113,7 @@ static void a4xx_enable_hwcg(struct msm_gpu *gpu) ...@@ -113,7 +113,7 @@ static void a4xx_enable_hwcg(struct msm_gpu *gpu)
} }
static void a4xx_me_init(struct msm_gpu *gpu) static bool a4xx_me_init(struct msm_gpu *gpu)
{ {
struct msm_ringbuffer *ring = gpu->rb; struct msm_ringbuffer *ring = gpu->rb;
...@@ -137,7 +137,7 @@ static void a4xx_me_init(struct msm_gpu *gpu) ...@@ -137,7 +137,7 @@ static void a4xx_me_init(struct msm_gpu *gpu)
OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000);
gpu->funcs->flush(gpu); gpu->funcs->flush(gpu);
gpu->funcs->idle(gpu); return gpu->funcs->idle(gpu);
} }
static int a4xx_hw_init(struct msm_gpu *gpu) static int a4xx_hw_init(struct msm_gpu *gpu)
...@@ -292,9 +292,7 @@ static int a4xx_hw_init(struct msm_gpu *gpu) ...@@ -292,9 +292,7 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
/* clear ME_HALT to start micro engine */ /* clear ME_HALT to start micro engine */
gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0); gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0);
a4xx_me_init(gpu); return a4xx_me_init(gpu) ? 0 : -EINVAL;
return 0;
} }
static void a4xx_recover(struct msm_gpu *gpu) static void a4xx_recover(struct msm_gpu *gpu)
...@@ -335,17 +333,21 @@ static void a4xx_destroy(struct msm_gpu *gpu) ...@@ -335,17 +333,21 @@ static void a4xx_destroy(struct msm_gpu *gpu)
kfree(a4xx_gpu); kfree(a4xx_gpu);
} }
static void a4xx_idle(struct msm_gpu *gpu) static bool a4xx_idle(struct msm_gpu *gpu)
{ {
/* wait for ringbuffer to drain: */ /* wait for ringbuffer to drain: */
adreno_idle(gpu); if (!adreno_idle(gpu))
return false;
/* then wait for GPU to finish: */ /* then wait for GPU to finish: */
if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) & if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) &
A4XX_RBBM_STATUS_GPU_BUSY))) A4XX_RBBM_STATUS_GPU_BUSY))) {
DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
/* TODO maybe we need to reset GPU here to recover from hang? */
return false;
}
/* TODO maybe we need to reset GPU here to recover from hang? */ return true;
} }
static irqreturn_t a4xx_irq(struct msm_gpu *gpu) static irqreturn_t a4xx_irq(struct msm_gpu *gpu)
......
...@@ -218,19 +218,18 @@ void adreno_flush(struct msm_gpu *gpu) ...@@ -218,19 +218,18 @@ void adreno_flush(struct msm_gpu *gpu)
adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr); adreno_gpu_write(adreno_gpu, REG_ADRENO_CP_RB_WPTR, wptr);
} }
void adreno_idle(struct msm_gpu *gpu) bool adreno_idle(struct msm_gpu *gpu)
{ {
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
uint32_t wptr = get_wptr(gpu->rb); uint32_t wptr = get_wptr(gpu->rb);
int ret;
/* wait for CP to drain ringbuffer: */ /* wait for CP to drain ringbuffer: */
ret = spin_until(get_rptr(adreno_gpu) == wptr); if (!spin_until(get_rptr(adreno_gpu) == wptr))
return true;
if (ret)
DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
/* TODO maybe we need to reset GPU here to recover from hang? */ /* TODO maybe we need to reset GPU here to recover from hang? */
DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
return false;
} }
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
......
...@@ -182,7 +182,7 @@ void adreno_recover(struct msm_gpu *gpu); ...@@ -182,7 +182,7 @@ void adreno_recover(struct msm_gpu *gpu);
void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
struct msm_file_private *ctx); struct msm_file_private *ctx);
void adreno_flush(struct msm_gpu *gpu); void adreno_flush(struct msm_gpu *gpu);
void adreno_idle(struct msm_gpu *gpu); bool adreno_idle(struct msm_gpu *gpu);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void adreno_show(struct msm_gpu *gpu, struct seq_file *m); void adreno_show(struct msm_gpu *gpu, struct seq_file *m);
#endif #endif
......
...@@ -50,7 +50,7 @@ struct msm_gpu_funcs { ...@@ -50,7 +50,7 @@ struct msm_gpu_funcs {
void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit, void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit,
struct msm_file_private *ctx); struct msm_file_private *ctx);
void (*flush)(struct msm_gpu *gpu); void (*flush)(struct msm_gpu *gpu);
void (*idle)(struct msm_gpu *gpu); bool (*idle)(struct msm_gpu *gpu);
irqreturn_t (*irq)(struct msm_gpu *irq); irqreturn_t (*irq)(struct msm_gpu *irq);
uint32_t (*last_fence)(struct msm_gpu *gpu); uint32_t (*last_fence)(struct msm_gpu *gpu);
void (*recover)(struct msm_gpu *gpu); void (*recover)(struct msm_gpu *gpu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment