To support boosting, vbios' seems to have fasters cstate than the actual base clock. We should definitly drop all those with a higher voltage than the max voltage stated in the vbios.
This fixes reclocking issues mostly on high-end kepler cards where the highest cstates goes way beyond the max voltage supported v2: don't depend on the order of the vid entries --- drm/nouveau/include/nvkm/subdev/volt.h | 4 ++++ drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++++ drm/nouveau/nvkm/subdev/volt/base.c | 18 ++++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/volt.h b/drm/nouveau/include/nvkm/subdev/volt.h index b458d04..32c1a22 100644 --- a/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drm/nouveau/include/nvkm/subdev/volt.h @@ -12,8 +12,12 @@ struct nvkm_volt { u32 uv; u8 vid; } vid[256]; + + u32 max_voltage; + u32 min_voltage; }; +int nvkm_volt_map(struct nvkm_volt *volt, u8 id); int nvkm_volt_get(struct nvkm_volt *); int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition); diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index dc8682c..d731bc3 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -138,16 +138,22 @@ static int nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) { struct nvkm_bios *bios = clk->subdev.device->bios; + struct nvkm_volt *volt = clk->subdev.device->volt; const struct nvkm_domain *domain = clk->domains; struct nvkm_cstate *cstate = NULL; struct nvbios_cstepX cstepX; u8 ver, hdr; u16 data; + int voltage; data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX); if (!data) return -ENOENT; + voltage = nvkm_volt_map(volt, cstepX.voltage); + if (volt && (voltage > volt->max_voltage || voltage < volt->min_voltage)) + return -EINVAL; + cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); if (!cstate) return -ENOMEM; diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c index 50b5649..7104168 100644 --- a/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drm/nouveau/nvkm/subdev/volt/base.c @@ -65,7 +65,7 @@ nvkm_volt_set(struct nvkm_volt *volt, u32 uv) return ret; } -static int +int nvkm_volt_map(struct nvkm_volt *volt, u8 id) { struct nvkm_bios *bios = volt->subdev.device->bios; @@ -120,6 +120,9 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); if (data && info.vidmask && info.base && info.step) { + volt->min_voltage = info.min; + volt->max_voltage = info.max; + for (i = 0; i < info.vidmask + 1; i++) { if (info.base >= info.min && info.base <= info.max) { @@ -138,9 +141,18 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) volt->vid[volt->vid_nr].uv = ivid.voltage; volt->vid[volt->vid_nr].vid = ivid.vid; volt->vid_nr++; + + if (volt->min_voltage == 0) + volt->min_voltage = ivid.voltage; + else + volt->min_voltage = min(volt->min_voltage, ivid.voltage); + volt->max_voltage = max(volt->max_voltage, ivid.voltage); } } volt->vid_mask = info.vidmask; + } else if (data && info.type == NVBIOS_VOLT_PWM) { + volt->min_voltage = info.base; + volt->max_voltage = info.base + info.pwm_range; } } @@ -181,8 +193,10 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, volt->func = func; /* Assuming the non-bios device should build the voltage table later */ - if (bios) + if (bios) { nvkm_volt_parse_bios(bios, volt); + nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", volt->min_voltage, volt->max_voltage); + } if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { -- 2.6.3 _______________________________________________ Nouveau mailing list Nouveau@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/nouveau