mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-11 15:11:48 -04:00
Merge "msm: kgsl: Simplify GBIF halt sequence for stall-on-fault case"
This commit is contained in:
commit
4f677ecb1b
4 changed files with 54 additions and 89 deletions
|
|
@ -1264,6 +1264,29 @@ void a6xx_gx_cpr_toggle(struct kgsl_device *device)
|
|||
wmb();
|
||||
}
|
||||
|
||||
/* This is only defined for non-GMU and non-RGMU targets */
|
||||
static int a6xx_clear_pending_transactions(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
int ret;
|
||||
|
||||
if (adreno_is_a619_holi(adreno_dev)) {
|
||||
kgsl_regwrite(device, A6XX_RBBM_GPR0_CNTL, 0x1e0);
|
||||
ret = adreno_wait_for_halt_ack(device,
|
||||
A6XX_RBBM_VBIF_GX_RESET_STATUS, 0xf0);
|
||||
} else {
|
||||
kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
ret = adreno_wait_for_halt_ack(device, A6XX_RBBM_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return a6xx_halt_gbif(adreno_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* a6xx_reset() - Helper function to reset the GPU
|
||||
* @device: Pointer to the KGSL device structure for the GPU
|
||||
|
|
@ -1277,19 +1300,9 @@ static int a6xx_reset(struct kgsl_device *device)
|
|||
int ret;
|
||||
unsigned long flags = device->pwrctrl.ctrl_flags;
|
||||
|
||||
/*
|
||||
* Stall on fault needs GBIF halt sequences for robust recovery.
|
||||
* Because in a worst-case scenario, if any of the GPU blocks is
|
||||
* generating a stream of un-ending faulting transactions, SMMU will
|
||||
* process those transactions when we try to resume it and enter
|
||||
* stall-on-fault mode again. GBIF halt sequences make sure that all
|
||||
* GPU transactions are halted at GBIF which ensures that SMMU
|
||||
* can resume safely.
|
||||
*/
|
||||
a6xx_do_gbif_halt(adreno_dev, A6XX_RBBM_GBIF_HALT,
|
||||
A6XX_RBBM_GBIF_HALT_ACK, A6XX_GBIF_GX_HALT_MASK, "GX");
|
||||
a6xx_do_gbif_halt(adreno_dev, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_ARB_HALT_MASK, "CX");
|
||||
ret = a6xx_clear_pending_transactions(adreno_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Clear ctrl_flags to ensure clocks and regulators are turned off */
|
||||
device->pwrctrl.ctrl_flags = 0;
|
||||
|
|
@ -2441,63 +2454,6 @@ u64 a6xx_read_alwayson(struct adreno_device *adreno_dev)
|
|||
return (((u64) hi) << 32) | lo;
|
||||
}
|
||||
|
||||
void a6xx_do_gbif_halt(struct adreno_device *adreno_dev,
|
||||
u32 halt_reg, u32 ack_reg, u32 mask, const char *client)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
unsigned long t;
|
||||
u32 val;
|
||||
|
||||
kgsl_regwrite(device, halt_reg, mask);
|
||||
|
||||
t = jiffies + msecs_to_jiffies(100);
|
||||
do {
|
||||
kgsl_regread(device, ack_reg, &val);
|
||||
if ((val & mask) == mask)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we are attempting GBIF halt in case of stall-on-fault
|
||||
* then the halt sequence will not complete as long as SMMU
|
||||
* is stalled.
|
||||
*/
|
||||
kgsl_mmu_pagefault_resume(&device->mmu);
|
||||
usleep_range(10, 100);
|
||||
} while (!time_after(jiffies, t));
|
||||
|
||||
/* Check one last time */
|
||||
kgsl_mmu_pagefault_resume(&device->mmu);
|
||||
|
||||
kgsl_regread(device, ack_reg, &val);
|
||||
if ((val & mask) == mask)
|
||||
return;
|
||||
|
||||
dev_err(device->dev, "%s GBIF Halt ack timed out\n", client);
|
||||
}
|
||||
|
||||
/* This is only defined for non-GMU and non-RGMU targets */
|
||||
static int a6xx_clear_pending_transactions(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
int ret;
|
||||
|
||||
if (adreno_is_a619_holi(adreno_dev)) {
|
||||
kgsl_regwrite(device, A6XX_RBBM_GPR0_CNTL, 0x1e0);
|
||||
ret = adreno_wait_for_halt_ack(device,
|
||||
A6XX_RBBM_VBIF_GX_RESET_STATUS, 0xf0);
|
||||
} else {
|
||||
kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
ret = adreno_wait_for_halt_ack(device, A6XX_RBBM_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return a6xx_halt_gbif(adreno_dev);
|
||||
}
|
||||
|
||||
const struct adreno_gpudev adreno_a6xx_gpudev = {
|
||||
.reg_offsets = a6xx_register_offsets,
|
||||
.probe = a6xx_probe,
|
||||
|
|
|
|||
|
|
@ -317,17 +317,6 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev);
|
|||
void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev);
|
||||
bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_do_gbif_halt - halt gbif traffic and wait for ack
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
* @halt_reg: reg to trigger gbif halt
|
||||
* @ack_reg: status register to check for ack
|
||||
* @mask: mask for ack
|
||||
* @client: client name - "GX" or "CX"
|
||||
*/
|
||||
void a6xx_do_gbif_halt(struct adreno_device *adreno_dev,
|
||||
u32 halt_reg, u32 ack_reg, u32 mask, const char *client);
|
||||
|
||||
/**
|
||||
* a6xx_read_alwayson - Read the current always on clock value
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
|
|
|
|||
|
|
@ -1617,15 +1617,15 @@ static void a6xx_gmu_pwrctrl_suspend(struct adreno_device *adreno_dev)
|
|||
|
||||
if (adreno_has_gbif(adreno_dev)) {
|
||||
/* Halt GX traffic */
|
||||
if (a6xx_gmu_gx_is_on(device))
|
||||
a6xx_do_gbif_halt(adreno_dev, A6XX_RBBM_GBIF_HALT,
|
||||
A6XX_RBBM_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_GX_HALT_MASK,
|
||||
"GX");
|
||||
|
||||
if (a6xx_gmu_gx_is_on(device)) {
|
||||
kgsl_regwrite(device, A6XX_RBBM_GBIF_HALT,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
adreno_wait_for_halt_ack(device,
|
||||
A6XX_RBBM_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_GX_HALT_MASK);
|
||||
}
|
||||
/* Halt CX traffic */
|
||||
a6xx_do_gbif_halt(adreno_dev, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK,
|
||||
A6XX_GBIF_ARB_HALT_MASK, "CX");
|
||||
a6xx_halt_gbif(adreno_dev);
|
||||
}
|
||||
|
||||
if (a6xx_gmu_gx_is_on(device))
|
||||
|
|
|
|||
|
|
@ -1747,6 +1747,26 @@ static void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu)
|
|||
struct kgsl_iommu_context *ctx = &iommu->user_context;
|
||||
|
||||
if (ctx->default_pt != NULL && ctx->stalled_on_fault) {
|
||||
u32 sctlr_val = KGSL_IOMMU_GET_CTX_REG(ctx,
|
||||
KGSL_IOMMU_CTX_SCTLR);
|
||||
|
||||
/*
|
||||
* As part of recovery, GBIF halt sequence should be performed.
|
||||
* In a worst case scenario, if any GPU block is generating a
|
||||
* stream of un-ending faulting transactions, SMMU would enter
|
||||
* stall-on-fault mode again after resuming and not let GBIF
|
||||
* halt succeed. In order to avoid that situation and terminate
|
||||
* those faulty transactions, set CFCFG and HUPCF to 0.
|
||||
*/
|
||||
sctlr_val &= ~(0x1 << KGSL_IOMMU_SCTLR_CFCFG_SHIFT);
|
||||
sctlr_val &= ~(0x1 << KGSL_IOMMU_SCTLR_HUPCF_SHIFT);
|
||||
KGSL_IOMMU_SET_CTX_REG(ctx, KGSL_IOMMU_CTX_SCTLR, sctlr_val);
|
||||
/*
|
||||
* Make sure the above register write is not reordered across
|
||||
* the barrier as we use writel_relaxed to write it.
|
||||
*/
|
||||
wmb();
|
||||
|
||||
/*
|
||||
* This will only clear fault bits in FSR. FSR.SS will still
|
||||
* be set. Writing to RESUME (below) is the only way to clear
|
||||
|
|
|
|||
Loading…
Reference in a new issue