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 <[email protected]> --- drm/nouveau/nvkm/subdev/clk/base.c | 63 +++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 5 deletions(-) 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); } -- 2.8.1 _______________________________________________ Nouveau mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/nouveau
