msm: kgsl: Take GMU snapshot on GMU failures

GMU can fail to turn on GX or it can fail the START HFI.
So take snapshot and put GMU in NMI. When this happens,
kgsl will call gmu_stop() and as GMU is already in fault
aka NMI, reset the GMU and GPU. If oob during adreno_stop
fails, take gmu snapshot and only do things that don't need
gx to be on.

Change-Id: Iafc9b34063a7ff2415d3462dd289b52e425fbf3b
Signed-off-by: Harshdeep Dhatt <hdhatt@codeaurora.org>
This commit is contained in:
Harshdeep Dhatt 2019-08-08 21:01:28 -06:00
commit 0d44684cab
2 changed files with 30 additions and 25 deletions

View file

@ -2057,12 +2057,16 @@ static int _adreno_start(struct adreno_device *adreno_dev)
/* Send OOB request to turn on the GX */
status = gmu_core_dev_oob_set(device, oob_gpu);
if (status)
goto error_boot_oob_clear;
if (status) {
gmu_core_snapshot(device);
goto error_oob_clear;
}
status = gmu_core_dev_hfi_start_msg(device);
if (status)
if (status) {
gmu_core_snapshot(device);
goto error_oob_clear;
}
if (device->pwrctrl.bus_control) {
/* VBIF waiting for RAM */
@ -2274,29 +2278,15 @@ static int adreno_stop(struct kgsl_device *device)
error = gmu_core_dev_oob_set(device, oob_gpu);
if (error) {
gmu_core_dev_oob_clear(device, oob_gpu);
if (gmu_core_regulator_isenabled(device)) {
/* GPU is on. Try recovery */
set_bit(GMU_FAULT, &device->gmu_core.flags);
gmu_core_snapshot(device);
error = -EINVAL;
}
goto no_gx_power;
}
adreno_dispatcher_stop(adreno_dev);
adreno_ringbuffer_stop(adreno_dev);
kgsl_pwrscale_update_stats(device);
adreno_irqctrl(adreno_dev, 0);
if (!IS_ERR_OR_NULL(adreno_dev->gpu_llc_slice))
llcc_slice_deactivate(adreno_dev->gpu_llc_slice);
if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice))
llcc_slice_deactivate(adreno_dev->gpuhtw_llc_slice);
/* Save active coresight registers if applicable */
adreno_coresight_stop(adreno_dev);
@ -2314,19 +2304,23 @@ static int adreno_stop(struct kgsl_device *device)
*/
if (!error && gmu_core_dev_wait_for_lowest_idle(device)) {
set_bit(GMU_FAULT, &device->gmu_core.flags);
gmu_core_snapshot(device);
/*
* Assume GMU hang after 10ms without responding.
* It shall be relative safe to clear vbif and stop
* MMU later. Early return in adreno_stop function
* will result in kernel panic in adreno_start
*/
error = -EINVAL;
}
adreno_clear_pending_transactions(device);
no_gx_power:
adreno_dispatcher_stop(adreno_dev);
adreno_ringbuffer_stop(adreno_dev);
if (!IS_ERR_OR_NULL(adreno_dev->gpu_llc_slice))
llcc_slice_deactivate(adreno_dev->gpu_llc_slice);
if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice))
llcc_slice_deactivate(adreno_dev->gpuhtw_llc_slice);
/*
* The halt is not cleared in the above function if we have GBIF.
* Clear it here if GMU is enabled as GMU stop needs access to

View file

@ -1674,6 +1674,12 @@ static void gmu_stop(struct kgsl_device *device)
if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags))
return;
/* Force suspend if gmu is already in fault */
if (test_bit(GMU_FAULT, &device->gmu_core.flags)) {
gmu_core_suspend(device);
return;
}
/* Wait for the lowest idle level we requested */
if (gmu_core_dev_wait_for_lowest_idle(device))
goto error;
@ -1701,6 +1707,11 @@ static void gmu_stop(struct kgsl_device *device)
error:
dev_err(&gmu->pdev->dev, "Failed to stop GMU\n");
gmu_core_snapshot(device);
/*
* We failed to stop the gmu successfully. Force a suspend
* to set things up for a fresh start.
*/
gmu_core_suspend(device);
}
static void gmu_remove(struct kgsl_device *device)