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: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>hifive-unleashed-5.1
parent
bcc188b77d
commit
c4a8d47560
|
@ -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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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);
|
||||||
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 {
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue