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
Seemingly Similar 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