# [v4,16/37] volt: don't require perfect fit

Submitted by Karol Herbst on April 18, 2016, 7:13 p.m.

## Details

Message ID 1461006851-5007-17-git-send-email-nouveau@karolherbst.de New show "Volting/Clocking improvements for Fermi and newer" ( rev: 4 ) in Nouveau

Not browsing as part of any series.

## Commit Message

Karol Herbst April 18, 2016, 7:13 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.

v3: simplify the implementation

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

```diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c
index d72bd4a..028c6e2 100644
--- a/drm/nouveau/nvkm/subdev/volt/base.c
+++ b/drm/nouveau/nvkm/subdev/volt/base.c
@@ -51,18 +51,30 @@  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, best_err = uv, 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);
-			nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
+		int err = volt->vid[i].uv - uv;
+		if (err < 0 || err > best_err)
+			continue;
+
+		best_err = err;
+		best = i;
+		if (best_err == 0)
break;
-		}
}
+
+	if (best == -1) {
+		nvkm_error(subdev, "couldn't set %iuv\n", uv);
+		return ret;
+	}
+
+	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;
}

```

```On 18/04/16 22:13, 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.
>
> v3: simplify the implementation
>
> Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
> ---
>   drm/nouveau/nvkm/subdev/volt/base.c | 22 +++++++++++++++++-----
>   1 file changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c
> index d72bd4a..028c6e2 100644
> --- a/drm/nouveau/nvkm/subdev/volt/base.c
> +++ b/drm/nouveau/nvkm/subdev/volt/base.c
> @@ -51,18 +51,30 @@ 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, best_err = uv, best = -1;

"best_err = uv" is not a safe value. You may set best_err to the maximum voltage, anything under that may fail in theory.

With this fixed, this is:

Reviewed-by: Martin Peres <martin.peres@free.fr>

>
>   	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);
> -			nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
> +		int err = volt->vid[i].uv - uv;
> +		if (err < 0 || err > best_err)
> +			continue;
> +
> +		best_err = err;
> +		best = i;
> +		if (best_err == 0)
>   			break;
> -		}
>   	}
> +
> +	if (best == -1) {
> +		nvkm_error(subdev, "couldn't set %iuv\n", uv);
> +		return ret;
> +	}
> +
> +	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;
>   }
>
```