Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f7f3d91 authored by Karol Herbst's avatar Karol Herbst Committed by Ben Skeggs
Browse files

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: default avatarKarol Herbst <karolherbst@gmail.com>
Reviewed-by: default avatarMartin Peres <martin.peres@free.fr>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 0d6f8100
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
+52 −0
Original line number Diff line number Diff line
@@ -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;
	}
+1 −1
Original line number Diff line number Diff line
@@ -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;