msm: kgsl: Dynamic AB voting based on actual bus transactions

Right now AB vote is calulated as a percentage of total possible BW
which causes higher AB vote than actual GPU bus transactions in some
use cases. We can calculate actual GPU bus BW if we know bus_width
for the target. This change will derive AB vote based on bus_width
defined in dtsi and VBIF counters.

Define bus_width in number of bytes in target gpu dtsi file to use
this new AB vote calculation.

Change-Id: I75d19c18649d9a87d20e3dbf7b623b772265fb5b
Signed-off-by: Mihir Patel <mihirp@codeaurora.org>
This commit is contained in:
Mihir Patel 2015-04-29 17:00:54 +05:30
parent e5c5e18d13
commit 72c4388425
6 changed files with 32 additions and 4 deletions

View File

@ -82,6 +82,8 @@ Optional Properties:
- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time
and when coming back out of resume
- qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency
- qcom,bus-width: Bus width in number of bytes. This enables dynamic AB bus voting based on
bus width and actual bus transactions.
- qcom,gpubw-dev: a phandle to a device representing bus bandwidth requirements
(see devdw.txt)
- qcom,idle-timeout: This property represents the time in microseconds for idle timeout.

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, 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
@ -23,6 +23,8 @@
#define HIST 5
#define TARGET 80
#define CAP 75
/* AB vote is in multiple of BW_STEP Mega bytes */
#define BW_STEP 160
static void _update_cutoff(struct devfreq_msm_adreno_tz_data *priv,
unsigned int norm_max)
@ -59,6 +61,7 @@ static int devfreq_gpubw_get_target(struct devfreq *df,
*/
static int norm_ab_max = 300;
int norm_ab;
unsigned long ab_mbytes = 0;
stats.private_data = &b;
@ -103,8 +106,15 @@ static int devfreq_gpubw_get_target(struct devfreq *df,
bus_profile->flag = DEVFREQ_FLAG_SLOW_HINT;
}
/* Re-calculate the AB percentage for a new IB vote */
if (bus_profile->flag) {
/* Calculate the AB vote based on bus width if defined */
if (priv->bus.width) {
norm_ab = (unsigned int)priv->bus.ram_time /
(unsigned int) priv->bus.total_time;
/* Calculate AB in Mega Bytes and roundup in BW_STEP */
ab_mbytes = (norm_ab * priv->bus.width * 1000000ULL) >> 20;
bus_profile->ab_mbytes = roundup(ab_mbytes, BW_STEP);
} else if (bus_profile->flag) {
/* Re-calculate the AB percentage for a new IB vote */
norm_ab = (unsigned int)priv->bus.ram_time /
(unsigned int) priv->bus.total_time;
if (norm_ab > norm_ab_max)

View File

@ -168,8 +168,10 @@ static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr,
return;
if (ib == 0)
*ab = 0;
else if (!pwr->bus_percent_ab)
else if ((!pwr->bus_percent_ab) && (!pwr->bus_ab_mbytes))
*ab = DEFAULT_BUS_P * ib / 100;
else if (pwr->bus_width)
*ab = pwr->bus_ab_mbytes;
else
*ab = (pwr->bus_percent_ab * max_bw) / 100;
@ -250,6 +252,8 @@ void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
} else {
/* If the bus is being turned off, reset to default level */
pwr->bus_mod = 0;
pwr->bus_percent_ab = 0;
pwr->bus_ab_mbytes = 0;
}
trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel);
last_vote_buslevel = buslevel;
@ -1553,6 +1557,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
/* Set if independent bus BW voting is supported */
pwr->bus_control = pdata->bus_control;
/* Bus width in bytes, set it to zero if not found */
if (of_property_read_u32(pdev->dev.of_node, "qcom,bus-width",
&pwr->bus_width))
pwr->bus_width = 0;
/* Check if gpu bandwidth vote device is defined in dts */
gpubw_dev_node = of_parse_phandle(pdev->dev.of_node,

View File

@ -108,6 +108,8 @@ struct kgsl_pwr_constraint {
* @bus_control - true if the bus calculation is independent
* @bus_mod - modifier from the current power level for the bus vote
* @bus_percent_ab - current percent of total possible bus usage
* @bus_width - target specific bus width in number of bytes
* @bus_ab_mbytes - AB vote in Mbytes for current bus usage
* @bus_index - default bus index into the bus_ib table
* @bus_ib - the set of unique ib requests needed for the bus calculation
* @constraint - currently active power constraint
@ -152,6 +154,8 @@ struct kgsl_pwrctrl {
bool bus_control;
int bus_mod;
unsigned int bus_percent_ab;
unsigned int bus_width;
unsigned long bus_ab_mbytes;
struct device *devbw;
unsigned int bus_index[KGSL_MAX_PWRLEVELS];
uint64_t *bus_ib;

View File

@ -715,6 +715,7 @@ int kgsl_busmon_target(struct device *dev, unsigned long *freq, u32 flags)
if (pwr->bus_mod != b) {
pwr->bus_percent_ab = device->pwrscale.bus_profile.percent_ab;
pwr->bus_ab_mbytes = device->pwrscale.bus_profile.ab_mbytes;
kgsl_pwrctrl_buslevel_update(device, true);
}
@ -797,6 +798,7 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
data->bus.num = out;
data->bus.ib = &pwr->bus_ib[0];
data->bus.index = &pwr->bus_index[0];
data->bus.width = pwr->bus_width;
} else
data->bus.num = 0;

View File

@ -36,6 +36,7 @@ struct devfreq_msm_adreno_tz_data {
u64 gpu_time;
u32 num;
u32 max;
u32 width;
u32 up[MSM_ADRENO_MAX_PWRLEVELS];
u32 down[MSM_ADRENO_MAX_PWRLEVELS];
u32 p_up[MSM_ADRENO_MAX_PWRLEVELS];
@ -61,6 +62,7 @@ struct msm_adreno_extended_profile {
struct msm_busmon_extended_profile {
u32 flag;
unsigned long percent_ab;
unsigned long ab_mbytes;
struct devfreq_msm_adreno_tz_data *private_data;
struct devfreq_dev_profile profile;
};