From 696ce310cf2542d3c163828beeae5a4d327e2612 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Fri, 14 Jul 2017 13:13:44 +0530 Subject: [PATCH] msm: kgsl: Set the abnormal power perf counter value to zero During preemption microcode does save restore for all perf counters. If we read the power counters at preemption boundary we might get abnormal value from the perf counter. This will result in showing incorrect GPU busy percentage. Fix this by setting the abnormal power perf counter value with zero. Change-Id: I96ba367ceeeb92d6adb507d0d917113297b4b58d Signed-off-by: Abhilash Kumar --- drivers/gpu/msm/adreno.h | 47 ++++++++++++++++++++++++++++++++--- drivers/gpu/msm/adreno_a3xx.c | 6 ++++- drivers/gpu/msm/adreno_a4xx.c | 6 ++++- drivers/gpu/msm/adreno_a5xx.c | 4 +++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 218d08e6dfc3..4a0acdcf8844 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -568,6 +568,8 @@ enum adreno_regs { ADRENO_REG_RBBM_RBBM_CTL, ADRENO_REG_UCHE_INVALIDATE0, ADRENO_REG_UCHE_INVALIDATE1, + ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, + ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, ADRENO_REG_RBBM_SECVID_TRUST_CONTROL, @@ -1508,21 +1510,60 @@ static inline void adreno_ringbuffer_set_pagetable(struct adreno_ringbuffer *rb, spin_unlock_irqrestore(&rb->preempt_lock, flags); } +static inline bool is_power_counter_overflow(struct adreno_device *adreno_dev, + unsigned int reg, unsigned int prev_val, unsigned int *perfctr_pwr_hi) +{ + unsigned int val; + bool ret = false; + + /* + * If prev_val is zero, it is first read after perf counter reset. + * So set perfctr_pwr_hi register to zero. + */ + if (prev_val == 0) { + *perfctr_pwr_hi = 0; + return ret; + } + adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val); + if (val != *perfctr_pwr_hi) { + *perfctr_pwr_hi = val; + ret = true; + } + return ret; +} + static inline unsigned int counter_delta(struct kgsl_device *device, unsigned int reg, unsigned int *counter) { + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int val; unsigned int ret = 0; + bool overflow = true; + static unsigned int perfctr_pwr_hi; /* Read the value */ kgsl_regread(device, reg, &val); + if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg + (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) + overflow = is_power_counter_overflow(adreno_dev, reg, + *counter, &perfctr_pwr_hi); + /* Return 0 for the first read */ if (*counter != 0) { - if (val < *counter) - ret = (0xFFFFFFFF - *counter) + val; - else + if (val >= *counter) { ret = val - *counter; + } else if (overflow == true) { + ret = (0xFFFFFFFF - *counter) + val; + } else { + /* + * Since KGSL got abnormal value from the counter, + * We will drop the value from being accumulated. + */ + pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n", + val, *counter, reg); + return 0; + } } *counter = val; diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 423071811b43..0e3e5b64bdc7 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1530,6 +1530,10 @@ static unsigned int a3xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A3XX_UCHE_CACHE_INVALIDATE0_REG), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A3XX_UCHE_CACHE_INVALIDATE1_REG), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, + A3XX_RBBM_PERFCTR_RBBM_0_LO), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, + A3XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A3XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index 5ca04e522270..6170cc263e4a 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -806,6 +806,10 @@ static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SW_RESET_CMD, A4XX_RBBM_SW_RESET_CMD), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A4XX_UCHE_INVALIDATE0), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A4XX_UCHE_INVALIDATE1), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, + A4XX_RBBM_PERFCTR_RBBM_0_LO), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, + A4XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A4XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI, diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 0715022be6e3..466c42877b3f 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -3069,6 +3069,10 @@ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_RBBM_BLOCK_SW_RESET_CMD2, A5XX_RBBM_BLOCK_SW_RESET_CMD2), ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A5XX_UCHE_INVALIDATE0), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO, + A5XX_RBBM_PERFCTR_RBBM_0_LO), + ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, + A5XX_RBBM_PERFCTR_RBBM_0_HI), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO, A5XX_RBBM_PERFCTR_LOAD_VALUE_LO), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,