[v2,16/22] volt: don't require perfect fit

Submitted by Karol Herbst on March 21, 2016, 4:16 p.m.

Details

Message ID 1458577000-6615-17-git-send-email-nouveau@karolherbst.de
State New
Headers show
Series "Volting/Clocking improvements for Fermi and newer" ( rev: 2 ) in Nouveau

Not browsing as part of any series.

Commit Message

Karol Herbst March 21, 2016, 4:16 p.m.
if we calculate the voltage in the table right, we get all kinds of values,
which never fit the hardware steps, so we use the closest higher value the
hardware can do

Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
---
 drm/nouveau/nvkm/subdev/volt/base.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c
index e741383..58738e3 100644
--- a/drm/nouveau/nvkm/subdev/volt/base.c
+++ b/drm/nouveau/nvkm/subdev/volt/base.c
@@ -51,18 +51,37 @@  static int
 nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
 {
 	struct nvkm_subdev *subdev = &volt->subdev;
-	int i, ret = -EINVAL;
+	int i, ret = -EINVAL, err, best = -1;
 
 	if (volt->func->volt_set)
 		return volt->func->volt_set(volt, uv);
 
 	for (i = 0; i < volt->vid_nr; i++) {
-		if (volt->vid[i].uv == uv) {
-			ret = volt->func->vid_set(volt, volt->vid[i].vid);
+		if (i == 0) {
+			best = 0;
+			err = volt->vid[i].uv - uv;
+		} else {
+			int new_err = volt->vid[i].uv - uv;
+			if (abs(new_err) < abs(err)
+			    || (err < 0 && new_err >= 0)) {
+				best = i;
+				err = new_err;
+			}
+		}
+
+		if (err == 0) {
+			ret = volt->func->vid_set(volt, volt->vid[best].vid);
 			nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
 			break;
 		}
 	}
+
+	if (best != -1) {
+		ret = volt->func->vid_set(volt, volt->vid[best].vid);
+		nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
+			   volt->vid[best].uv, ret);
+	}
+
 	return ret;
 }
 

Comments

On 21/03/16 18:16, Karol Herbst wrote:
> if we calculate the voltage in the table right, we get all kinds of values,
> which never fit the hardware steps, so we use the closest higher value the
> hardware can do

This is indeed the goal.

>
> Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
> ---
>   drm/nouveau/nvkm/subdev/volt/base.c | 25 ++++++++++++++++++++++---
>   1 file changed, 22 insertions(+), 3 deletions(-)
>
> diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c
> index e741383..58738e3 100644
> --- a/drm/nouveau/nvkm/subdev/volt/base.c
> +++ b/drm/nouveau/nvkm/subdev/volt/base.c
> @@ -51,18 +51,37 @@ static int
>   nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
>   {
>   	struct nvkm_subdev *subdev = &volt->subdev;
> -	int i, ret = -EINVAL;
> +	int i, ret = -EINVAL, err, best = -1;
>   
>   	if (volt->func->volt_set)
>   		return volt->func->volt_set(volt, uv);
>   
>   	for (i = 0; i < volt->vid_nr; i++) {
> -		if (volt->vid[i].uv == uv) {
> -			ret = volt->func->vid_set(volt, volt->vid[i].vid);
> +		if (i == 0) {
> +			best = 0;
> +			err = volt->vid[i].uv - uv;
> +		} else {
> +			int new_err = volt->vid[i].uv - uv;
> +			if (abs(new_err) < abs(err)
> +			    || (err < 0 && new_err >= 0)) {
> +				best = i;
> +				err = new_err;
> +			}
> +		}
> +
> +		if (err == 0) {
> +			ret = volt->func->vid_set(volt, volt->vid[best].vid);
>   			nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
>   			break;
>   		}
>   	}
> +
> +	if (best != -1) {
> +		ret = volt->func->vid_set(volt, volt->vid[best].vid);
> +		nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
> +			   volt->vid[best].uv, ret);
> +	}
> +
>   	return ret;
>   }

The code is really weird though :o How about the following? It would 
make it much more readable and actually do what your commit message says.

int best = -1;
u32 best_abs_err = -1;
for (i = 0; i < volt->vid_nr; i++) {
	int abs_err = abs(volt->vid[i].uv - uv);
	if (volt->vid[i].uv >= uv && abs_err < best_abs_err) {
		best = i;
		best_abs_err = abs_err;		
		if (abs_err == 0)
			break;
	 }
}

if (best >= 0) {
	ret = volt->func->vid_set(volt, volt->vid[best].vid);
	nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
} else {
	/* return an error to tell that we cannot use the wanted clock since we cannot select the needed voltage! */
}