Merge "msm: kgsl: Add GPU minimum bandwidth vote state"

This commit is contained in:
qctecmdr 2020-09-01 14:37:03 -07:00 • committed by Gerrit - the friendly Code Review server
commit 8295c46e6b
8 changed files with 137 additions and 18 deletions

View file

@ -1077,6 +1077,8 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev,
/* Default timeout is 80 ms across all targets */
device->pwrctrl.interval_timeout = msecs_to_jiffies(80);
device->pwrctrl.minbw_timeout = 10;
/* Set default bus control to true on all targets */
device->pwrctrl.bus_control = true;

View file

@ -60,7 +60,7 @@ ssize_t adreno_coresight_show_register(struct device *dev,
*/
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_NAP) {
kgsl_state_is_nap_or_minbw(device)) {
if (!adreno_active_count_get(adreno_dev)) {
if (!is_cx)
kgsl_regread(device, cattr->reg->offset,
@ -115,7 +115,7 @@ ssize_t adreno_coresight_store_register(struct device *dev,
/* Program the hardware if it is not power collapsed */
if (device->state == KGSL_STATE_ACTIVE ||
device->state == KGSL_STATE_NAP) {
kgsl_state_is_nap_or_minbw(device)) {
if (!adreno_active_count_get(adreno_dev)) {
if (!is_cx)
kgsl_regwrite(device, cattr->reg->offset,

View file

@ -31,7 +31,8 @@ static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr,
}
int kgsl_bus_update(struct kgsl_device *device, bool on)
int kgsl_bus_update(struct kgsl_device *device,
enum kgsl_bus_vote vote_state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* FIXME: this might be wrong? */
@ -40,17 +41,24 @@ int kgsl_bus_update(struct kgsl_device *device, bool on)
u32 ab;
/* the bus should be ON to update the active frequency */
if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
if ((vote_state != KGSL_BUS_VOTE_OFF) &&
!(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
return 0;
/*
* If the bus should remain on calculate our request and submit it,
* otherwise request bus level 0, off.
*/
if (on) {
if (vote_state == KGSL_BUS_VOTE_ON) {
buslevel = min_t(int, pwr->pwrlevels[0].bus_max,
cur + pwr->bus_mod);
buslevel = max_t(int, buslevel, 1);
} else {
} else if (vote_state == KGSL_BUS_VOTE_MINIMUM) {
/* Request bus level 1, minimum non-zero value */
buslevel = 1;
pwr->bus_mod = 0;
pwr->bus_percent_ab = 0;
pwr->bus_ab_mbytes = 0;
} else if (vote_state == KGSL_BUS_VOTE_OFF) {
/* If the bus is being turned off, reset to default level */
pwr->bus_mod = 0;
pwr->bus_percent_ab = 0;

View file

@ -6,12 +6,18 @@
#ifndef _KGSL_BUS_H
#define _KGSL_BUS_H
enum kgsl_bus_vote {
KGSL_BUS_VOTE_OFF = 0,
KGSL_BUS_VOTE_ON,
KGSL_BUS_VOTE_MINIMUM,
};
struct kgsl_device;
struct platform_device;
int kgsl_bus_init(struct kgsl_device *device, struct platform_device *pdev);
void kgsl_bus_close(struct kgsl_device *device);
int kgsl_bus_update(struct kgsl_device *device, bool on);
int kgsl_bus_update(struct kgsl_device *device, enum kgsl_bus_vote vote_state);
u32 *kgsl_bus_get_table(struct platform_device *pdev,
const char *name, int *count);

View file

@ -25,7 +25,8 @@
* past its timer) and all system resources are released. SUSPEND is *
* requested by the kernel and will be enforced upon all open devices. *
* RESET indicates that GPU or GMU hang happens. KGSL is handling *
* snapshot or recover GPU from hang. *
* snapshot or recover GPU from hang. MINBW implies that DDR BW vote is *
* set to non-zero minimum value.
*/
#define KGSL_STATE_NONE 0x00000000
@ -35,6 +36,7 @@
#define KGSL_STATE_SUSPEND 0x00000010
#define KGSL_STATE_AWARE 0x00000020
#define KGSL_STATE_SLUMBER 0x00000080
#define KGSL_STATE_MINBW 0x00000100
/**
* enum kgsl_event_results - result codes passed to an event callback when the
@ -596,6 +598,15 @@ static inline int kgsl_state_is_awake(struct kgsl_device *device)
return false;
}
static inline bool kgsl_state_is_nap_or_minbw(struct kgsl_device *device)
{
if (device->state == KGSL_STATE_NAP ||
device->state == KGSL_STATE_MINBW)
return true;
return false;
}
int kgsl_readtimestamp(struct kgsl_device *device, void *priv,
enum kgsl_timestamp_type type, unsigned int *timestamp);

View file

@ -196,7 +196,7 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
* Update the bus before the GPU clock to prevent underrun during
* frequency increases.
*/
kgsl_bus_update(device, true);
kgsl_bus_update(device, KGSL_BUS_VOTE_ON);
pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
/* Change register settings if any BEFORE pwrlevel change*/
@ -552,6 +552,33 @@ static ssize_t idle_timer_show(struct device *dev,
jiffies_to_msecs(device->pwrctrl.interval_timeout));
}
static ssize_t minbw_timer_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct kgsl_device *device = dev_get_drvdata(dev);
u32 val;
int ret;
if (device->pwrctrl.ctrl_flags & BIT(KGSL_PWRFLAGS_NAP_OFF))
return -EINVAL;
ret = kstrtou32(buf, 0, &val);
if (ret)
return ret;
device->pwrctrl.minbw_timeout = val;
return count;
}
static ssize_t minbw_timer_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct kgsl_device *device = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%u\n",
device->pwrctrl.minbw_timeout);
}
static ssize_t gpubusy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -1045,6 +1072,7 @@ static DEVICE_ATTR_RO(temp);
static DEVICE_ATTR_RW(gpuclk);
static DEVICE_ATTR_RW(max_gpuclk);
static DEVICE_ATTR_RW(idle_timer);
static DEVICE_ATTR_RW(minbw_timer);
static DEVICE_ATTR_RO(gpubusy);
static DEVICE_ATTR_RO(gpu_available_frequencies);
static DEVICE_ATTR_RO(gpu_clock_stats);
@ -1072,6 +1100,7 @@ static const struct attribute *pwrctrl_attr_list[] = {
&dev_attr_gpuclk.attr,
&dev_attr_max_gpuclk.attr,
&dev_attr_idle_timer.attr,
&dev_attr_minbw_timer.attr,
&dev_attr_gpubusy.attr,
&dev_attr_gpu_available_frequencies.attr,
&dev_attr_gpu_clock_stats.attr,
@ -1183,7 +1212,8 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
clk_disable(pwr->grp_clks[i]);
/* High latency clock maintenance. */
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
(requested_state != KGSL_STATE_NAP)) {
(requested_state != KGSL_STATE_NAP) &&
(requested_state != KGSL_STATE_MINBW)) {
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
clk_unprepare(pwr->grp_clks[i]);
device->ftbl->gpu_clock_set(device,
@ -1211,7 +1241,8 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
trace_kgsl_clk(device, state,
kgsl_pwrctrl_active_freq(pwr));
/* High latency clock maintenance. */
if (device->state != KGSL_STATE_NAP) {
if ((device->state != KGSL_STATE_NAP) &&
(device->state != KGSL_STATE_MINBW)) {
if (pwr->pwrlevels[0].gpu_freq > 0) {
device->ftbl->gpu_clock_set(device,
pwr->active_pwrlevel);
@ -1257,13 +1288,13 @@ int kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
&pwr->power_flags)) {
trace_kgsl_bus(device, state);
return kgsl_bus_update(device, false);
return kgsl_bus_update(device, KGSL_BUS_VOTE_OFF);
}
} else if (state == KGSL_PWRFLAGS_ON) {
if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
&pwr->power_flags)) {
trace_kgsl_bus(device, state);
return kgsl_bus_update(device, true);
return kgsl_bus_update(device, KGSL_BUS_VOTE_ON);
}
}
@ -1354,6 +1385,18 @@ void kgsl_pwrctrl_irq(struct kgsl_device *device, int state)
}
}
static void kgsl_minbw_timer(struct timer_list *t)
{
struct kgsl_pwrctrl *pwr = from_timer(pwr, t, minbw_timer);
struct kgsl_device *device = container_of(pwr,
struct kgsl_device, pwrctrl);
if (device->state == KGSL_STATE_NAP) {
kgsl_pwrctrl_request_state(device, KGSL_STATE_MINBW);
kgsl_schedule_work(&device->idle_check_ws);
}
}
static int _get_clocks(struct kgsl_device *device)
{
struct device *dev = &device->pdev->dev;
@ -1417,7 +1460,7 @@ static void _gpu_clk_prepare_enable(struct kgsl_device *device,
{
int ret;
if (device->state == KGSL_STATE_NAP) {
if (kgsl_state_is_nap_or_minbw(device)) {
ret = clk_enable(clk);
if (ret)
goto err;
@ -1529,6 +1572,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
pm_runtime_enable(&pdev->dev);
timer_setup(&pwr->minbw_timer, kgsl_minbw_timer, 0);
/* temperature sensor name */
of_property_read_string(pdev->dev.of_node, "qcom,tzone-name",
&pwr->tzone_name);
@ -1559,7 +1604,7 @@ void kgsl_idle_check(struct work_struct *work)
requested_state = device->requested_state;
if (device->state == KGSL_STATE_ACTIVE
|| device->state == KGSL_STATE_NAP) {
|| kgsl_state_is_nap_or_minbw(device)) {
if (!atomic_read(&device->active_cnt)) {
spin_lock(&device->submit_lock);
@ -1599,7 +1644,9 @@ done:
jiffies +
device->pwrctrl.interval_timeout);
}
kgsl_pwrscale_update(device);
if (device->state != KGSL_STATE_MINBW)
kgsl_pwrscale_update(device);
mutex_unlock(&device->mutex);
}
@ -1711,7 +1758,10 @@ static int _init(struct kgsl_device *device)
int status = 0;
switch (device->state) {
case KGSL_STATE_MINBW:
/* fall through */
case KGSL_STATE_NAP:
del_timer_sync(&device->pwrctrl.minbw_timer);
/* Force power on to do the stop */
status = kgsl_pwrctrl_enable(device);
/* fall through */
@ -1764,6 +1814,9 @@ static int _wake(struct kgsl_device *device)
kgsl_pwrscale_wake(device);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
/* fall through */
case KGSL_STATE_MINBW:
kgsl_bus_update(device, KGSL_BUS_VOTE_ON);
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
@ -1785,6 +1838,7 @@ static int _wake(struct kgsl_device *device)
pwr->previous_pwrlevel = pwr->active_pwrlevel;
mod_timer(&device->idle_timer, jiffies +
device->pwrctrl.interval_timeout);
del_timer_sync(&device->pwrctrl.minbw_timer);
break;
case KGSL_STATE_AWARE:
kgsl_pwrctrl_clk_set_options(device, true);
@ -1793,6 +1847,7 @@ static int _wake(struct kgsl_device *device)
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
mod_timer(&device->idle_timer, jiffies +
device->pwrctrl.interval_timeout);
del_timer_sync(&device->pwrctrl.minbw_timer);
break;
default:
dev_warn(device->dev, "unhandled state %s\n",
@ -1823,7 +1878,9 @@ _aware(struct kgsl_device *device)
case KGSL_STATE_INIT:
status = kgsl_pwrctrl_enable(device);
break;
/* The following 3 cases shouldn't occur, but don't panic. */
/* The following 4 cases shouldn't occur, but don't panic. */
case KGSL_STATE_MINBW:
/* Fall through */
case KGSL_STATE_NAP:
status = _wake(device);
/* Fall through */
@ -1867,6 +1924,9 @@ _nap(struct kgsl_device *device)
*/
kgsl_pwrscale_update_stats(device);
mod_timer(&device->pwrctrl.minbw_timer, jiffies +
msecs_to_jiffies(device->pwrctrl.minbw_timeout));
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
/* fallthrough */
@ -1883,6 +1943,26 @@ _nap(struct kgsl_device *device)
return 0;
}
static int
_minbw(struct kgsl_device *device)
{
switch (device->state) {
/*
* Device is expected to be clock gated to move to
* a deeper low power state. No other transition is
* permitted
*/
case KGSL_STATE_NAP:
kgsl_bus_update(device, KGSL_BUS_VOTE_MINIMUM);
kgsl_pwrctrl_set_state(device, KGSL_STATE_MINBW);
break;
default:
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
break;
}
return 0;
}
static int
_slumber(struct kgsl_device *device)
{
@ -1896,6 +1976,9 @@ _slumber(struct kgsl_device *device)
}
/* fall through */
case KGSL_STATE_NAP:
/* fall through */
case KGSL_STATE_MINBW:
del_timer_sync(&device->pwrctrl.minbw_timer);
del_timer_sync(&device->idle_timer);
kgsl_pwrscale_midframe_timer_cancel(device);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
@ -1999,6 +2082,9 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state)
case KGSL_STATE_NAP:
status = _nap(device);
break;
case KGSL_STATE_MINBW:
status = _minbw(device);
break;
case KGSL_STATE_SLUMBER:
status = _slumber(device);
break;
@ -2051,6 +2137,8 @@ const char *kgsl_pwrstate_to_str(unsigned int state)
return "ACTIVE";
case KGSL_STATE_NAP:
return "NAP";
case KGSL_STATE_MINBW:
return "MINBW";
case KGSL_STATE_SUSPEND:
return "SUSPEND";
case KGSL_STATE_SLUMBER:

View file

@ -163,6 +163,10 @@ struct kgsl_pwrctrl {
struct icc_path *icc_path;
/** cur_ab: The last ab voted by the driver */
u32 cur_ab;
/** @minbw_timer - Timer struct for entering minimum bandwidth state */
struct timer_list minbw_timer;
/** @minbw_timeout - Timeout for entering minimum bandwidth state */
u32 minbw_timeout;
};
int kgsl_pwrctrl_init(struct kgsl_device *device);

View file

@ -588,7 +588,7 @@ int kgsl_busmon_target(struct device *dev, unsigned long *freq, u32 flags)
if ((pwr->bus_mod != b) || (pwr->bus_ab_mbytes != ab_mbytes)) {
pwr->bus_percent_ab = device->pwrscale.bus_profile.percent_ab;
pwr->bus_ab_mbytes = ab_mbytes;
kgsl_bus_update(device, true);
kgsl_bus_update(device, KGSL_BUS_VOTE_ON);
}
mutex_unlock(&device->mutex);