Karol Herbst
2015-Nov-23 10:00 UTC
[Nouveau] [PATCH 0/2] Fix some voltage issues found on Kepler cards
With these both patches, most of the kepler cards should be able to reclock their core clock without issues. These patches should be tested carefully among nouveau devs, so that these don't break reclocking on other cards (especially Teslas). Particularly the second one might break reclocking here and there. Karol Herbst (2): bios/volt: handle voltage table version 0x50 with 0ed header clk: drop cstates with too high voltage drm/nouveau/include/nvkm/subdev/volt.h | 4 ++++ drm/nouveau/nvkm/subdev/bios/volt.c | 3 +++ drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++++ drm/nouveau/nvkm/subdev/volt/base.c | 17 +++++++++++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) -- 2.6.3
Karol Herbst
2015-Nov-23 10:00 UTC
[Nouveau] [PATCH 1/2] bios/volt: handle voltage table version 0x50 with 0ed header
Some Kepler cards have no usefull header in the voltage table, which means nouveau has to read the voltages out of the entries directly. This patch fixes volting issues on those cards enabling them to switch cstates Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/nvkm/subdev/bios/volt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/bios/volt.c b/drm/nouveau/nvkm/subdev/bios/volt.c index 6e0a336..fd2776b 100644 --- a/drm/nouveau/nvkm/subdev/bios/volt.c +++ b/drm/nouveau/nvkm/subdev/bios/volt.c @@ -142,7 +142,10 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, info->vid = nvbios_rd08(bios, volt + 0x01) >> 2; break; case 0x40: + break; case 0x50: + info->voltage = nvbios_rd32(bios, volt) & 0x001fffff; + info->vid = idx; break; } return volt; -- 2.6.3
Karol Herbst
2015-Nov-23 10:00 UTC
[Nouveau] [PATCH 2/2] clk: drop cstates with too high voltage
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 Signed-off-by: Karol Herbst <nouveau at karolherbst.de> --- drm/nouveau/include/nvkm/subdev/volt.h | 4 ++++ drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++++ drm/nouveau/nvkm/subdev/volt/base.c | 17 +++++++++++++++-- 3 files changed, 25 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..b300060 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,17 @@ 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 (i == 0) + volt->min_voltage = ivid.voltage; } + + 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 +192,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
Maybe Matching Threads
- [RFC PATCH v2 0/7] stabilize kepler reclocking
- [RFC PATCH 0/5] stabilize kepler reclocking
- [PATCH 00/19] Volting/Clocking improvements for Fermi and newer
- [PATCH v2 00/22] Volting/Clocking improvements for Fermi and newer
- [PATCH 0/9] Groundwork for clocking fixes