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

Martin Peres martin.peres at free.fr
Tue Apr 19 21:04:30 UTC 2016


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 <nouveau at karolherbst.de>
> ---
>   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; &cstate->head != &pstate->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, &pstate->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(&pstate->list)) {
> -		if (cstatei == -1)
> -			cstate = list_entry(pstate->list.prev, typeof(*cstate),
> -					    head);
> -		else {
> -			list_for_each_entry(cstate, &pstate->list, head) {
> -				if (cstate->cstate == cstatei)
> -					break;
> -			}
> -		}
> +		cstate = nvkm_cstate_get(clk, pstate, cstatei);
> +		cstate = nvkm_cstate_find_best(clk, pstate, cstate);
>   	} else {
>   		cstate = &pstate->base;
>   	}

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


More information about the Nouveau mailing list