Re: [Nouveau] [PATCH v4 13/37] clk: respect voltage limits in nvkm_cstate_prog

2016-04-19 Thread Martin Peres

On 18/04/16 22:13, Karol Herbst wrote:

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.

this resolves all remaining volting errors on fermi and newer.

v3: use find_best for all cstates before actually trying
 add nvkm_cstate_get function to get cstate by index

Signed-off-by: Karol Herbst 
---
  drm/nouveau/nvkm/subdev/clk/base.c | 83 +-
  1 file changed, 74 insertions(+), 9 deletions(-)

diff --git a/drm/nouveau/nvkm/subdev/clk/base.c 
b/drm/nouveau/nvkm/subdev/clk/base.c
index fecf58f..21f6369 100644
--- a/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drm/nouveau/nvkm/subdev/clk/base.c
@@ -74,6 +74,78 @@ 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) &&
+  voltage >= volt->min_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_therm *therm = device->therm;
+   struct nvkm_volt *volt = device->volt;
+   struct nvkm_cstate *cstate;
+   int max_volt, temp = 0;
+
+   if (!pstate || !start)
+   return NULL;
+
+   if (!volt)
+   return start;
+
+   if (therm) {
+   /* ignore error code */
+   temp = max(0, nvkm_therm_temp_get(therm));
+   }
+
+   max_volt = volt->max_uv;
+   if (volt->max0_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max0_id, temp));
+   if (volt->max1_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max1_id, temp));
+   if (volt->max2_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max2_id, temp));
+
+   for (cstate = start; >head != >list;
+cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) {
+   if (nvkm_cstate_valid(clk, cstate, max_volt, temp))
+   break;
+   }
+
+   return cstate;
+}
+
+static struct nvkm_cstate *
+nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
+{
+   struct nvkm_cstate *cstate;
+   if (cstatei == -1)
+   return list_entry(pstate->list.prev, typeof(*cstate), head);
+   else {
+   list_for_each_entry(cstate, >list, head) {
+   if (cstate->cstate == cstatei)
+   return cstate;
+   }
+   }
+   return NULL;
+}
+
  static int
  nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int 
cstatei)
  {
@@ -85,15 +157,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate 
*pstate, int cstatei)
int ret;
  
  	if (!list_empty(>list)) {

-   if (cstatei == -1)
-   cstate = list_entry(pstate->list.prev, typeof(*cstate),
-   head);
-   else {
-   list_for_each_entry(cstate, >list, head) {
-   if (cstate->cstate == cstatei)
-   break;
-   }
-   }
+   cstate = nvkm_cstate_get(clk, pstate, cstatei);
+   cstate = nvkm_cstate_find_best(clk, pstate, cstate);
} else {
cstate = >base;
}


Reviewed-by: Martin Peres 
___
Nouveau mailing list
Nouveau@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/nouveau


[Nouveau] [PATCH v4 13/37] clk: respect voltage limits in nvkm_cstate_prog

2016-04-18 Thread Karol Herbst
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.

this resolves all remaining volting errors on fermi and newer.

v3: use find_best for all cstates before actually trying
add nvkm_cstate_get function to get cstate by index

Signed-off-by: Karol Herbst 
---
 drm/nouveau/nvkm/subdev/clk/base.c | 83 +-
 1 file changed, 74 insertions(+), 9 deletions(-)

diff --git a/drm/nouveau/nvkm/subdev/clk/base.c 
b/drm/nouveau/nvkm/subdev/clk/base.c
index fecf58f..21f6369 100644
--- a/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drm/nouveau/nvkm/subdev/clk/base.c
@@ -74,6 +74,78 @@ 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) &&
+  voltage >= volt->min_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_therm *therm = device->therm;
+   struct nvkm_volt *volt = device->volt;
+   struct nvkm_cstate *cstate;
+   int max_volt, temp = 0;
+
+   if (!pstate || !start)
+   return NULL;
+
+   if (!volt)
+   return start;
+
+   if (therm) {
+   /* ignore error code */
+   temp = max(0, nvkm_therm_temp_get(therm));
+   }
+
+   max_volt = volt->max_uv;
+   if (volt->max0_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max0_id, temp));
+   if (volt->max1_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max1_id, temp));
+   if (volt->max2_id != 0xff)
+   max_volt = min(max_volt,
+  nvkm_volt_map(volt, volt->max2_id, temp));
+
+   for (cstate = start; >head != >list;
+cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) {
+   if (nvkm_cstate_valid(clk, cstate, max_volt, temp))
+   break;
+   }
+
+   return cstate;
+}
+
+static struct nvkm_cstate *
+nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
+{
+   struct nvkm_cstate *cstate;
+   if (cstatei == -1)
+   return list_entry(pstate->list.prev, typeof(*cstate), head);
+   else {
+   list_for_each_entry(cstate, >list, head) {
+   if (cstate->cstate == cstatei)
+   return cstate;
+   }
+   }
+   return NULL;
+}
+
 static int
 nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
 {
@@ -85,15 +157,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate 
*pstate, int cstatei)
int ret;
 
if (!list_empty(>list)) {
-   if (cstatei == -1)
-   cstate = list_entry(pstate->list.prev, typeof(*cstate),
-   head);
-   else {
-   list_for_each_entry(cstate, >list, head) {
-   if (cstate->cstate == cstatei)
-   break;
-   }
-   }
+   cstate = nvkm_cstate_get(clk, pstate, cstatei);
+   cstate = nvkm_cstate_find_best(clk, pstate, cstate);
} else {
cstate = >base;
}
-- 
2.8.1

___
Nouveau mailing list
Nouveau@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/nouveau