[v3,28/29] clk: only do partial reclocks as required

Submitted by Karol Herbst on April 7, 2016, 9:24 p.m.

Details

Message ID 1460064259-1243-29-git-send-email-nouveau@karolherbst.de
State New
Headers show
Series "Volting/Clocking improvements for Fermi and newer" ( rev: 3 ) in Nouveau

Not browsing as part of any series.

Commit Message

Karol Herbst April 7, 2016, 9:24 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.

Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
---
 drm/nouveau/nvkm/subdev/clk/base.c | 63 +++++++++++++++++++++++++++++++++++---
 1 file changed, 58 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 50a4e36..e7101e1 100644
--- a/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drm/nouveau/nvkm/subdev/clk/base.c
@@ -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) {
@@ -318,6 +323,24 @@  nvkm_pstate_prog(struct nvkm_clk *clk, int pstateid)
 	return nvkm_cstate_prog(clk, pstate, clk->exp_cstate);
 }
 
+static int
+nvkm_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;
+	int ret;
+
+	if (!volt || !therm || !clk->pstate || !clk->set_cstate)
+		return -EINVAL;
+
+	ret =  nvkm_volt_set_id(volt, clk->set_cstate->voltage,
+				clk->pstate->base.voltage, -1);
+	ret |= nvkm_volt_set_id(volt, clk->set_cstate->voltage,
+				clk->pstate->base.voltage, +1);
+	return ret;
+}
+
 static void
 nvkm_clk_update_work(struct work_struct *work)
 {
@@ -344,13 +367,43 @@  nvkm_clk_update_work(struct work_struct *work)
 		pstate = -1;
 	}
 
-	nvkm_trace(subdev, "-> %d\n", pstate);
-	ret = nvkm_pstate_prog(clk, pstate);
-	if (ret) {
-		nvkm_error(subdev, "error setting pstate %d: %d\n",
-			   pstate, 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, "couldn't find fitting cstate\n");
+			goto update_err;
+		}
+
+		cstate = nvkm_cstate_find_best(clk, clk->pstate, cstate);
+		if (!cstate) {
+			nvkm_error(subdev, "couldn't find best cstate\n");
+			goto update_err;
+		}
+
+		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 {
+			nvkm_clk_update_volt(clk);
+		}
+	} else {
+		nvkm_clk_update_volt(clk);
 	}
 
+update_err:
 	wake_up_all(&clk->wait);
 	nvkm_notify_get(&clk->pwrsrc_ntfy);
 }