[v4,32/37] clk: only do partial reclocks as required

Submitted by Karol Herbst on April 18, 2016, 7:14 p.m.

Details

Message ID 1461006851-5007-33-git-send-email-nouveau@karolherbst.de
State New
Headers show
Series "Volting/Clocking improvements for Fermi and newer" ( rev: 4 ) in Nouveau

Not browsing as part of any series.

Commit Message

Karol Herbst April 18, 2016, 7:14 p.m.
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

Signed-off-by: Karol Herbst <nouveau@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(-)

Patch hide | download patch | download mbox

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

Comments

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@free.fr>

>
> Signed-off-by: Karol Herbst <nouveau@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