gpu: nvgpu: cache gpu clk rate

Cache the rate used in clk_set_rate().
Return that cached rate on clk_get_rate(), don't read from hardware.
This cached rate is used to avoid duplicate requests to clk_set_rate().

Motivation is to support multiple governors for gpu clk.
Reading clock from hardware is unreliable in multi-governor situation.
Relying on hardware clock value could mislead the kernel gpu governor
in its scaling calculations.

Bug 2051688

Change-Id: I43fc056eea6f69fe0889c45640fcb892b658071c
Signed-off-by: Arun Kannan <akannan@nvidia.com>
(cherry picked from commit 7f819a9ba7)
Reviewed-on: https://git-master.nvidia.com/r/1662759
Reviewed-on: https://git-master.nvidia.com/r/1668919
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Arun Kannan
2018-03-05 14:32:08 -08:00
committed by mobile promotions
parent 0e3181a5d7
commit e9a6d179a4
5 changed files with 28 additions and 7 deletions

View File

@@ -1,7 +1,7 @@
/*
* Linux clock support
*
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -34,9 +34,13 @@ static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain)
switch (api_domain) {
case CTRL_CLK_DOMAIN_GPCCLK:
if (g->clk.tegra_clk)
ret = clk_get_rate(g->clk.tegra_clk);
ret = g->clk.cached_rate ?
g->clk.cached_rate :
clk_get_rate(g->clk.tegra_clk);
else
ret = clk_get_rate(platform->clk[0]);
ret = platform->cached_rate ?
platform->cached_rate :
clk_get_rate(platform->clk[0]);
break;
case CTRL_CLK_DOMAIN_PWRCLK:
ret = clk_get_rate(platform->clk[1]);
@@ -58,10 +62,15 @@ static int nvgpu_linux_clk_set_rate(struct gk20a *g,
switch (api_domain) {
case CTRL_CLK_DOMAIN_GPCCLK:
if (g->clk.tegra_clk)
if (g->clk.tegra_clk) {
ret = clk_set_rate(g->clk.tegra_clk, rate);
else
if (!ret)
g->clk.cached_rate = rate;
} else {
ret = clk_set_rate(platform->clk[0], rate);
if (!ret)
platform->cached_rate = rate;
}
break;
case CTRL_CLK_DOMAIN_PWRCLK:
ret = clk_set_rate(platform->clk[1], rate);

View File

@@ -256,6 +256,9 @@ struct gk20a_platform {
/* stream id to use */
u32 ltc_streamid;
/* scaling rate */
unsigned long cached_rate;
};
static inline struct gk20a_platform *gk20a_get_platform(

View File

@@ -506,6 +506,8 @@ static int gk20a_tegra_get_clocks(struct device *dev)
rate = clk_round_rate(c, rate);
clk_set_rate(c, rate);
platform->clk[i] = c;
if (i == 0)
platform->cached_rate = rate;
}
platform->num_clks = i;

View File

@@ -57,11 +57,13 @@ gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP];
#define EMC_BW_RATIO (TEGRA_GP10B_BW_PER_FREQ / TEGRA_DDR4_BW_PER_FREQ)
#define GPCCLK_INIT_RATE 1000000000
static struct {
char *name;
unsigned long default_rate;
} tegra_gp10b_clocks[] = {
{"gpu", 1000000000},
{"gpu", GPCCLK_INIT_RATE},
{"gpu_sys", 204000000} };
static void gr_gp10b_remove_sysfs(struct device *dev);
@@ -90,6 +92,8 @@ int gp10b_tegra_get_clocks(struct device *dev)
} else {
clk_set_rate(c, rate);
platform->clk[i] = c;
if (i == 0)
platform->cached_rate = rate;
}
}
platform->num_clks = i;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 - 2017, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2011 - 2018, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -96,6 +96,9 @@ struct clk_gk20a {
#if defined(CONFIG_COMMON_CLK)
struct clk *tegra_clk;
struct clk_hw hw;
/* scaling rate */
unsigned long cached_rate;
#endif
struct pll gpc_pll;
struct pll gpc_pll_last;