From 1f7f3d91ad38afc706f838fb5a642b21d28e4485 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sat, 16 Jul 2016 15:26:25 +0200 Subject: [PATCH] drm/nouveau/clk: Respect voltage limits in nvkm_cstate_prog We should never allow to select a cstate which current voltage (depending on the temperature) is higher than 1. the max volt entries in the voltage map table. 2. what tha gpu actually can volt to. v3: Use find_best for all cstates before actually trying. Add nvkm_cstate_get function to get cstate by index. v5: Cstates with voltages lower then min_uv are valid. Move nvkm_cstate_get into the previous commit. Signed-off-by: Karol Herbst Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/volt.h | 1 + .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 52 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/volt/base.c | 2 +- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index 6fd933df763e..441f6e7079d2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -27,6 +27,7 @@ struct nvkm_volt { u8 max2_id; }; +int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature); int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id); int nvkm_volt_get(struct nvkm_volt *); int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 688c908908d8..60392b2edcbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -74,6 +74,57 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, /****************************************************************************** * C-States *****************************************************************************/ +static bool +nvkm_cstate_valid(struct nvkm_clk *clk, struct nvkm_cstate *cstate, + u32 max_volt, int temp) +{ + struct nvkm_volt *volt = clk->subdev.device->volt; + int voltage; + + if (!volt) + return true; + + voltage = nvkm_volt_map(volt, cstate->voltage, temp); + if (voltage < 0) + return false; + return voltage <= min(max_volt, volt->max_uv); +} + +static struct nvkm_cstate * +nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate, + struct nvkm_cstate *start) +{ + struct nvkm_device *device = clk->subdev.device; + struct nvkm_volt *volt = device->volt; + struct nvkm_cstate *cstate; + int max_volt; + + if (!pstate || !start) + return NULL; + + if (!volt) + return start; + + max_volt = volt->max_uv; + if (volt->max0_id != 0xff) + max_volt = min(max_volt, + nvkm_volt_map(volt, volt->max0_id, clk->temp)); + if (volt->max1_id != 0xff) + max_volt = min(max_volt, + nvkm_volt_map(volt, volt->max1_id, clk->temp)); + if (volt->max2_id != 0xff) + max_volt = min(max_volt, + nvkm_volt_map(volt, volt->max2_id, clk->temp)); + + for (cstate = start; &cstate->head != &pstate->list; + cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) { + if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp)) + break; + } + + return cstate; +} + static struct nvkm_cstate * nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { @@ -101,6 +152,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) if (!list_empty(&pstate->list)) { cstate = nvkm_cstate_get(clk, pstate, cstatei); + cstate = nvkm_cstate_find_best(clk, pstate, cstate); } else { cstate = &pstate->base; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 40ba088a5c81..5e07bd3aaccc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -88,7 +88,7 @@ nvkm_volt_map_min(struct nvkm_volt *volt, u8 id) return id ? id * 10000 : -ENODEV; } -static int +int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp) { struct nvkm_bios *bios = volt->subdev.device->bios;