[Nouveau] [PATCH v4 32/37] clk: only do partial reclocks as required
Martin Peres
martin.peres at free.fr
Wed Apr 20 22:17:13 UTC 2016
On 18/04/16 22:14, Karol Herbst wrote:
> we don't want to reclock to the same pstate or cstate over and over again, so
> only do things we actually have to do.
>
> v4: move into gf100
Reviewed-by: Martin Peres <martin.peres at free.fr>
>
> Signed-off-by: Karol Herbst <nouveau at karolherbst.de>
> ---
> drm/nouveau/nvkm/subdev/clk/base.c | 11 +++++--
> drm/nouveau/nvkm/subdev/clk/gf100.c | 62 ++++++++++++++++++++++++++++++++++++-
> drm/nouveau/nvkm/subdev/clk/gk104.c | 2 +-
> drm/nouveau/nvkm/subdev/clk/nv40.c | 3 ++
> drm/nouveau/nvkm/subdev/clk/priv.h | 4 +++
> 5 files changed, 77 insertions(+), 5 deletions(-)
>
> diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c
> index 3c40f67..2776d79 100644
> --- a/drm/nouveau/nvkm/subdev/clk/base.c
> +++ b/drm/nouveau/nvkm/subdev/clk/base.c
> @@ -107,7 +107,7 @@ nvkm_cstate_valid(struct nvkm_clk *clk, struct nvkm_cstate *cstate, u32 max_volt
> voltage >= volt->min_uv;
> }
>
> -static struct nvkm_cstate *
> +struct nvkm_cstate *
> nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
> struct nvkm_cstate *start)
> {
> @@ -148,7 +148,7 @@ nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
> return cstate;
> }
>
> -static struct nvkm_cstate *
> +struct nvkm_cstate *
> nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
> {
> struct nvkm_cstate *cstate;
> @@ -168,7 +168,7 @@ nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
> return NULL;
> }
>
> -static int
> +int
> nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
> {
> struct nvkm_subdev *subdev = &clk->subdev;
> @@ -188,6 +188,11 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
> cstate = &pstate->base;
> }
>
> + if (!cstate) {
> + nvkm_error(subdev, "failed to set cstate %d\n", cstatei);
> + return -EINVAL;
> + }
> +
> if (therm) {
> ret = nvkm_therm_cstate(therm, pstate->fanspeed, +1);
> if (ret && ret != -ENODEV) {
> diff --git a/drm/nouveau/nvkm/subdev/clk/gf100.c b/drm/nouveau/nvkm/subdev/clk/gf100.c
> index 808e1ed..5025dcc 100644
> --- a/drm/nouveau/nvkm/subdev/clk/gf100.c
> +++ b/drm/nouveau/nvkm/subdev/clk/gf100.c
> @@ -28,6 +28,7 @@
> #include <subdev/bios.h>
> #include <subdev/bios/pll.h>
> #include <subdev/timer.h>
> +#include <subdev/volt.h>
>
> struct gf100_clk_info {
> u32 freq;
> @@ -431,13 +432,72 @@ gf100_clk_tidy(struct nvkm_clk *base)
> memset(clk->eng, 0x00, sizeof(clk->eng));
> }
>
> +static int
> +gf100_clk_update_volt(struct nvkm_clk *clk)
> +{
> + struct nvkm_subdev *subdev = &clk->subdev;
> + struct nvkm_volt *volt = subdev->device->volt;
> + struct nvkm_therm *therm = subdev->device->therm;
> +
> + if (!volt || !therm || !clk->pstate || !clk->set_cstate)
> + return -EINVAL;
> +
> + return nvkm_volt_set_id(volt, clk->set_cstate->voltage,
> + clk->pstate->base.voltage, 0);
> +}
> +
> +void
> +gf100_clk_update(struct nvkm_clk *clk, int pstate)
> +{
> + struct nvkm_subdev *subdev = &clk->subdev;
> + int ret;
> +
> + if (!clk->pstate || clk->pstate->pstate != pstate) {
> + nvkm_trace(subdev, "-> P %d\n", pstate);
> + ret = nvkm_pstate_prog(clk, pstate);
> + if (ret) {
> + nvkm_error(subdev, "error setting pstate %d: %d\n",
> + pstate, ret);
> + }
> + } else if (!clk->set_cstate ||
> + clk->set_cstate->cstate != clk->exp_cstate) {
> +
> + struct nvkm_cstate *cstate = nvkm_cstate_get(clk, clk->pstate, clk->exp_cstate);
> + if (!cstate) {
> + nvkm_error(subdev, "can't find cstate %i\n",
> + clk->exp_cstate);
> + return;
> + }
> +
> + cstate = nvkm_cstate_find_best(clk, clk->pstate, cstate);
> + if (!cstate) {
> + nvkm_error(subdev, "can't find best cstate for %i\n",
> + cstate->cstate);
> + return;
> + }
> +
> + if (cstate != clk->set_cstate) {
> + nvkm_trace(subdev, "-> C %d\n", cstate->cstate);
> + ret = nvkm_cstate_prog(clk, clk->pstate, cstate->cstate);
> + if (ret) {
> + nvkm_error(subdev, "error setting cstate %d: %d\n",
> + cstate->cstate, ret);
> + }
> + } else {
> + gf100_clk_update_volt(clk);
> + }
> + } else {
> + gf100_clk_update_volt(clk);
> + }
> +}
> +
> static const struct nvkm_clk_func
> gf100_clk = {
> .read = gf100_clk_read,
> .calc = gf100_clk_calc,
> .prog = gf100_clk_prog,
> .tidy = gf100_clk_tidy,
> - .update = nv40_clk_update,
> + .update = gf100_clk_update,
> .domains = {
> { nv_clk_src_crystal, 0xff },
> { nv_clk_src_href , 0xff },
> diff --git a/drm/nouveau/nvkm/subdev/clk/gk104.c b/drm/nouveau/nvkm/subdev/clk/gk104.c
> index 8448a88..abf1d76 100644
> --- a/drm/nouveau/nvkm/subdev/clk/gk104.c
> +++ b/drm/nouveau/nvkm/subdev/clk/gk104.c
> @@ -482,7 +482,7 @@ gk104_clk = {
> .calc = gk104_clk_calc,
> .prog = gk104_clk_prog,
> .tidy = gk104_clk_tidy,
> - .update = nv40_clk_update,
> + .update = gf100_clk_update,
> .domains = {
> { nv_clk_src_crystal, 0xff },
> { nv_clk_src_href , 0xff },
> diff --git a/drm/nouveau/nvkm/subdev/clk/nv40.c b/drm/nouveau/nvkm/subdev/clk/nv40.c
> index a808319..5b10ee2 100644
> --- a/drm/nouveau/nvkm/subdev/clk/nv40.c
> +++ b/drm/nouveau/nvkm/subdev/clk/nv40.c
> @@ -207,6 +207,9 @@ nv40_clk_update(struct nvkm_clk *clk, int pstate)
> struct nvkm_subdev *subdev = &clk->subdev;
> int ret;
>
> + if (clk->pstate && clk->pstate->pstate == pstate)
> + return;
> +
> nvkm_trace(subdev, "-> %d\n", pstate);
> ret = nvkm_pstate_prog(clk, pstate);
> if (ret) {
> diff --git a/drm/nouveau/nvkm/subdev/clk/priv.h b/drm/nouveau/nvkm/subdev/clk/priv.h
> index 958f5e3..e2f15c4 100644
> --- a/drm/nouveau/nvkm/subdev/clk/priv.h
> +++ b/drm/nouveau/nvkm/subdev/clk/priv.h
> @@ -22,10 +22,14 @@ int nvkm_clk_new_(const struct nvkm_clk_func *, struct nvkm_device *, int,
> bool allow_reclock, struct nvkm_clk **);
>
> int nvkm_pstate_prog(struct nvkm_clk *, int pstateid);
> +int nvkm_cstate_prog(struct nvkm_clk *, struct nvkm_pstate *, int cstatei);
> +struct nvkm_cstate * nvkm_cstate_get(struct nvkm_clk *, struct nvkm_pstate *, int cstatei);
> +struct nvkm_cstate * nvkm_cstate_find_best(struct nvkm_clk *, struct nvkm_pstate *, struct nvkm_cstate *start);
>
> int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk,
> struct nvkm_pll_vals *);
> int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *);
>
> void nv40_clk_update(struct nvkm_clk *, int pstate);
> +void gf100_clk_update(struct nvkm_clk *, int pstate);
> #endif
More information about the Nouveau
mailing list