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: Karol Herbst <karolherbst@gmail.com> Reviewed-by: Martin Peres <martin.peres@free.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Родитель
0d6f81003e
Коммит
1f7f3d91ad
|
@ -27,6 +27,7 @@ struct nvkm_volt {
|
||||||
u8 max2_id;
|
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_map_min(struct nvkm_volt *volt, u8 id);
|
||||||
int nvkm_volt_get(struct nvkm_volt *);
|
int nvkm_volt_get(struct nvkm_volt *);
|
||||||
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
|
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
|
||||||
|
|
|
@ -74,6 +74,57 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* C-States
|
* 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 *
|
static struct nvkm_cstate *
|
||||||
nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
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)) {
|
if (!list_empty(&pstate->list)) {
|
||||||
cstate = nvkm_cstate_get(clk, pstate, cstatei);
|
cstate = nvkm_cstate_get(clk, pstate, cstatei);
|
||||||
|
cstate = nvkm_cstate_find_best(clk, pstate, cstate);
|
||||||
} else {
|
} else {
|
||||||
cstate = &pstate->base;
|
cstate = &pstate->base;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ nvkm_volt_map_min(struct nvkm_volt *volt, u8 id)
|
||||||
return id ? id * 10000 : -ENODEV;
|
return id ? id * 10000 : -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
|
nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
|
||||||
{
|
{
|
||||||
struct nvkm_bios *bios = volt->subdev.device->bios;
|
struct nvkm_bios *bios = volt->subdev.device->bios;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче