Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [RFC PATCH v2 0/7] stabilize kepler reclocking
this series solves different issues we encounter on kepler cards while reclocking: 1. core clock doesn't change at all and produces a volting error (patch 1) this can happen when the voltage table has only 0ed values in the header so we have to parse the entries itself, which contain the right voltages 2. kepler won't clock to highest cstates (patch 2) this happens, because there are entries in the cstep table with too high voltages attached in this case we should simply drop those cstates, because they can't even be used by the gpu the voltage limit is found in the voltage map table 3. higher voltage used than on blob/Windows (patch 3-4) this happened, because previously nouveau didn't know how the read the max voltage for boosting out of the vbios like patch 2 we simply drop all cstates with voltage higher than this one 4. heat issues after clocking to highest pstate (patch 5-7) sometimes the gpu is able to handle the highest cstate, but the gpu isn't build for that high voltages in that case we should just parse the baseclock table, which tells us the clocks the gpu is intented to run with the last patches also introduce a new config option: NvBoost 0: no boosting/cstates, this will stick with the base clocks from the PM_Mode table 1: highest clock available is the base clock (default) 2: highest clock available is the boost clock 3: all cstates are available (still limited by gpu and boost voltage) because this will regress performance on some cards, the new option should be advertised later on, but I think it is a better idea to be safe here, because otherwise nouveau can easily go above the TDP of the gpu and this leads to complete different issues. After this, we can then try to understand which factors are important for boosting and implement it in a better way, but for this we need: 1. support for power consumption sensors 2. better understanding on which power budget is the right one 3. in which situation we can boost how far Because this series can mess up reclocking for a wide range of cards, I really want to have it tested on several systems, thanks Karol Herbst (7): bios/volt: handle voltage table version 0x50 with 0ed header clk: drop cstates with too high voltage volt: parse the boost voltage entry clk: drop cstates with higher voltage than boost_max_voltage nvbios: add parsing of BASE CLOCK table subdev/clk: print the base clocks clk: allow boosting only when NvBoost is set drm/nouveau/include/nvkm/subdev/bios/baseclock.h | 23 +++++++ drm/nouveau/include/nvkm/subdev/bios/vmap.h | 1 + drm/nouveau/include/nvkm/subdev/clk.h | 10 ++- drm/nouveau/include/nvkm/subdev/volt.h | 6 ++ drm/nouveau/nvkm/subdev/bios/Kbuild | 1 + drm/nouveau/nvkm/subdev/bios/baseclock.c | 79 ++++++++++++++++++++++++ drm/nouveau/nvkm/subdev/bios/vmap.c | 5 +- drm/nouveau/nvkm/subdev/bios/volt.c | 3 + drm/nouveau/nvkm/subdev/clk/base.c | 41 +++++++++++- drm/nouveau/nvkm/subdev/clk/gf100.c | 2 +- drm/nouveau/nvkm/subdev/clk/gk104.c | 2 +- drm/nouveau/nvkm/subdev/volt/base.c | 26 +++++++- 12 files changed, 192 insertions(+), 7 deletions(-) create mode 100644 drm/nouveau/include/nvkm/subdev/bios/baseclock.h create mode 100644 drm/nouveau/nvkm/subdev/bios/baseclock.c -- 2.6.3
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 1/7] 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 --- 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-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 2/7] 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 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
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 3/7] volt: parse the boost voltage entry
--- drm/nouveau/include/nvkm/subdev/bios/vmap.h | 1 + drm/nouveau/include/nvkm/subdev/volt.h | 2 ++ drm/nouveau/nvkm/subdev/bios/vmap.c | 5 ++++- drm/nouveau/nvkm/subdev/volt/base.c | 8 ++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drm/nouveau/include/nvkm/subdev/bios/vmap.h b/drm/nouveau/include/nvkm/subdev/bios/vmap.h index 6633c6d..1e170c7 100644 --- a/drm/nouveau/include/nvkm/subdev/bios/vmap.h +++ b/drm/nouveau/include/nvkm/subdev/bios/vmap.h @@ -1,6 +1,7 @@ #ifndef __NVBIOS_VMAP_H__ #define __NVBIOS_VMAP_H__ struct nvbios_vmap { + u8 boost; }; u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); diff --git a/drm/nouveau/include/nvkm/subdev/volt.h b/drm/nouveau/include/nvkm/subdev/volt.h index 32c1a22..085f65f 100644 --- a/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drm/nouveau/include/nvkm/subdev/volt.h @@ -15,6 +15,8 @@ struct nvkm_volt { u32 max_voltage; u32 min_voltage; + + u32 boost_max_voltage; }; int nvkm_volt_map(struct nvkm_volt *volt, u8 id); diff --git a/drm/nouveau/nvkm/subdev/bios/vmap.c b/drm/nouveau/nvkm/subdev/bios/vmap.c index 2f13db7..9b0ab33 100644 --- a/drm/nouveau/nvkm/subdev/bios/vmap.c +++ b/drm/nouveau/nvkm/subdev/bios/vmap.c @@ -60,8 +60,11 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); switch (!!vmap * *ver) { - case 0x10: case 0x20: + info->boost = nvbios_rd08(bios, vmap + 0x7); + break; + case 0x10: + info->boost = 0xff; break; } return vmap; diff --git a/drm/nouveau/nvkm/subdev/volt/base.c b/drm/nouveau/nvkm/subdev/volt/base.c index 7104168..763ec0b 100644 --- a/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drm/nouveau/nvkm/subdev/volt/base.c @@ -194,8 +194,16 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, /* Assuming the non-bios device should build the voltage table later */ if (bios) { + u8 ver, hdr, cnt, len; + struct nvbios_vmap vmap; + nvkm_volt_parse_bios(bios, volt); nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", volt->min_voltage, volt->max_voltage); + + if (nvbios_vmap_parse(bios, &ver, &hdr, &cnt, &len, &vmap) && vmap.boost != 0xff) { + volt->boost_max_voltage = nvkm_volt_map(volt, vmap.boost); + nvkm_debug(&volt->subdev, "max boost voltage: %iuv\n", volt->boost_max_voltage); + } } if (volt->vid_nr) { -- 2.6.3
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 4/7] clk: drop cstates with higher voltage than boost_max_voltage
--- drm/nouveau/nvkm/subdev/clk/base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index d731bc3..43abca7 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -154,6 +154,9 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) if (volt && (voltage > volt->max_voltage || voltage < volt->min_voltage)) return -EINVAL; + if (volt && volt->boost_max_voltage && (voltage > volt->boost_max_voltage)) + return -EINVAL; + cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); if (!cstate) return -ENOMEM; -- 2.6.3
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 5/7] nvbios: add parsing of BASE CLOCK table
--- drm/nouveau/include/nvkm/subdev/bios/baseclock.h | 23 +++++++ drm/nouveau/nvkm/subdev/bios/Kbuild | 1 + drm/nouveau/nvkm/subdev/bios/baseclock.c | 79 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 drm/nouveau/include/nvkm/subdev/bios/baseclock.h create mode 100644 drm/nouveau/nvkm/subdev/bios/baseclock.c diff --git a/drm/nouveau/include/nvkm/subdev/bios/baseclock.h b/drm/nouveau/include/nvkm/subdev/bios/baseclock.h new file mode 100644 index 0000000..07ee355 --- /dev/null +++ b/drm/nouveau/include/nvkm/subdev/bios/baseclock.h @@ -0,0 +1,23 @@ +#ifndef __NVBIOS_BASECLOCK_H__ +#define __NVBIOS_BASECLOCK_H__ +struct nvbios_baseclock_header { + u16 offset; + + u8 version; + u8 hlen; + u8 ecount; + u8 elen; + u8 scount; + u8 slen; + + u8 base_entry; + u8 boost_entry; + u8 tdp_entry; +}; +struct nvbios_baseclock_entry { + u8 pstate; + u16 clock_mhz; +}; +int nvbios_baseclock_parse(struct nvkm_bios *, struct nvbios_baseclock_header *); +int nvbios_baseclock_get_entry(struct nvkm_bios *, struct nvbios_baseclock_header *h, u8 idx, struct nvbios_baseclock_entry *); +#endif diff --git a/drm/nouveau/nvkm/subdev/bios/Kbuild b/drm/nouveau/nvkm/subdev/bios/Kbuild index 64730d5..a402755 100644 --- a/drm/nouveau/nvkm/subdev/bios/Kbuild +++ b/drm/nouveau/nvkm/subdev/bios/Kbuild @@ -1,4 +1,5 @@ nvkm-y += nvkm/subdev/bios/base.o +nvkm-y += nvkm/subdev/bios/baseclock.o nvkm-y += nvkm/subdev/bios/bit.o nvkm-y += nvkm/subdev/bios/boost.o nvkm-y += nvkm/subdev/bios/conn.o diff --git a/drm/nouveau/nvkm/subdev/bios/baseclock.c b/drm/nouveau/nvkm/subdev/bios/baseclock.c new file mode 100644 index 0000000..31609e0 --- /dev/null +++ b/drm/nouveau/nvkm/subdev/bios/baseclock.c @@ -0,0 +1,79 @@ +/* + * Copyright 2015 Nouveau Community + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Karol Herbst + */ +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/baseclock.h> + +static u16 +nvbios_baseclock_offset(struct nvkm_bios *b) +{ + struct bit_entry bit_P; + + if (!bit_entry(b, 'P', &bit_P)) { + if (bit_P.version == 2) + return nvbios_rd16(b, bit_P.offset + 0x38); + } + + return 0x0000; +} + +int nvbios_baseclock_parse(struct nvkm_bios *b, struct nvbios_baseclock_header *h) +{ + if (!h) + return -EINVAL; + + h->offset = nvbios_baseclock_offset(b); + if (!h->offset) + return -ENODEV; + + h->version = nvbios_rd08(b, h->offset); + switch (h->version) { + case 0x10: + h->hlen = nvbios_rd08(b, h->offset + 0x1); + h->elen = nvbios_rd08(b, h->offset + 0x2); + h->slen = nvbios_rd08(b, h->offset + 0x3); + h->scount = nvbios_rd08(b, h->offset + 0x4); + h->ecount = nvbios_rd08(b, h->offset + 0x5); + + h->base_entry = nvbios_rd08(b, h->offset + 0x0f); + h->boost_entry = nvbios_rd08(b, h->offset + 0x10); + h->tdp_entry = nvbios_rd08(b, h->offset + 0x11); + return 0; + default: + return -EINVAL; + } +} + +int nvbios_baseclock_get_entry(struct nvkm_bios *b, struct nvbios_baseclock_header *h, u8 idx, struct nvbios_baseclock_entry *e) +{ + u16 offset; + + if (!e || !h) + return -EINVAL; + + offset = h->offset + h->hlen + idx * (h->elen + (h->slen * h->scount)); + e->pstate = nvbios_rd08(b, offset); + e->clock_mhz = nvbios_rd16(b, offset + 0x5); + return 0; +} -- 2.6.3
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 6/7] subdev/clk: print the base clocks
--- drm/nouveau/nvkm/subdev/clk/base.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index 43abca7..7cb9dd8 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -24,6 +24,7 @@ #include "priv.h" #include <subdev/bios.h> +#include <subdev/bios/baseclock.h> #include <subdev/bios/boost.h> #include <subdev/bios/cstep.h> #include <subdev/bios/perf.h> @@ -565,10 +566,25 @@ int nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, int index, bool allow_reclock, struct nvkm_clk *clk) { + struct nvkm_bios *bios; int ret, idx, arglen; const char *mode; + struct nvbios_baseclock_header header; nvkm_subdev_ctor(&nvkm_clk, device, index, 0, &clk->subdev); + bios = device->bios; + + if (bios && !nvbios_baseclock_parse(bios, &header)) { + struct nvbios_baseclock_entry base_entry, boost_entry; + if (nvbios_baseclock_get_entry(bios, &header, header.base_entry, &base_entry)) + nvkm_error(&clk->subdev, "couldn't parse base clock\n"); + else if (nvbios_baseclock_get_entry(bios, &header, header.boost_entry, &boost_entry)) + nvkm_error(&clk->subdev, "couldn't parse boost clock\n"); + else + nvkm_info(&clk->subdev, "base: %i MHz, boost: %i MHz\n", + base_entry.clock_mhz / 2, boost_entry.clock_mhz / 2); + } + clk->func = func; INIT_LIST_HEAD(&clk->states); clk->domains = func->domains; -- 2.6.3
Karol Herbst
2015-Dec-02 16:24 UTC
[Nouveau] [PATCH v2 7/7] clk: allow boosting only when NvBoost is set
0: disable boosting (use fixed clocks from PM_Mode table) 1: boost only to base clock from the vbios (default) 2: boost only to boost clock from the vbios 3: boost to max clock available (still limited by gpu and boost voltage) --- drm/nouveau/include/nvkm/subdev/clk.h | 10 +++++++++- drm/nouveau/nvkm/subdev/clk/base.c | 18 ++++++++++++++++-- drm/nouveau/nvkm/subdev/clk/gf100.c | 2 +- drm/nouveau/nvkm/subdev/clk/gk104.c | 2 +- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index 8708f0a..8085d81 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -64,7 +64,8 @@ struct nvkm_pstate { struct nvkm_domain { enum nv_clk_src name; u8 bios; /* 0xff for none */ -#define NVKM_CLK_DOM_FLAG_CORE 0x01 +#define NVKM_CLK_DOM_FLAG_CORE 0x01 +#define NVKM_CLK_DOM_FLAG_BASE_CLOCK_CORE 0x02 u8 flags; const char *mname; int mdiv; @@ -94,6 +95,13 @@ struct nvkm_clk { int dstate; /* display adjustment (min+) */ bool allow_reclock; +#define NVKM_CLK_BOOST_MODE_NONE 0x0 +#define NVKM_CLK_BOOST_MODE_AVG 0x1 +#define NVKM_CLK_BOOST_MODE_FULL 0x2 + u8 boost_mode; + + u32 base_clock; + u32 boost_clock; /*XXX: die, these are here *only* to support the completely * bat-shit insane what-was-nouveau_hw.c code diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index 7cb9dd8..7da0ae3 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -169,6 +169,12 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { u32 freq = nvkm_clk_adjust(clk, true, pstate->pstate, domain->bios, cstepX.freq); + if (domain->flags & NVKM_CLK_DOM_FLAG_BASE_CLOCK_CORE) { + if (clk->boost_mode == 1 && freq > clk->base_clock) + goto err; + if (clk->boost_mode == 2 && freq > clk->boost_clock) + goto err; + } cstate->domain[domain->name] = freq; } domain++; @@ -176,6 +182,9 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) list_add(&cstate->head, &pstate->list); return 0; +err: + kfree(cstate); + return -EINVAL; } /****************************************************************************** @@ -366,7 +375,7 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx) } data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE); - if (data) { + if (data && clk->boost_mode > 0) { int idx = cstepE.index; do { nvkm_cstate_new(clk, idx, pstate); @@ -574,15 +583,20 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, nvkm_subdev_ctor(&nvkm_clk, device, index, 0, &clk->subdev); bios = device->bios; + clk->boost_mode = 0; if (bios && !nvbios_baseclock_parse(bios, &header)) { struct nvbios_baseclock_entry base_entry, boost_entry; if (nvbios_baseclock_get_entry(bios, &header, header.base_entry, &base_entry)) nvkm_error(&clk->subdev, "couldn't parse base clock\n"); else if (nvbios_baseclock_get_entry(bios, &header, header.boost_entry, &boost_entry)) nvkm_error(&clk->subdev, "couldn't parse boost clock\n"); - else + else { + clk->boost_mode = nvkm_longopt(device->cfgopt, "NvBoost", 1); + clk->base_clock = base_entry.clock_mhz * 1000; + clk->boost_clock = boost_entry.clock_mhz * 1000; nvkm_info(&clk->subdev, "base: %i MHz, boost: %i MHz\n", base_entry.clock_mhz / 2, boost_entry.clock_mhz / 2); + } } clk->func = func; diff --git a/drm/nouveau/nvkm/subdev/clk/gf100.c b/drm/nouveau/nvkm/subdev/clk/gf100.c index a52b7e7..eaf4f83 100644 --- a/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -443,7 +443,7 @@ gf100_clk = { { nv_clk_src_hubk06 , 0x00 }, { nv_clk_src_hubk01 , 0x01 }, { nv_clk_src_copy , 0x02 }, - { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, + { nv_clk_src_gpc , 0x03, NVKM_CLK_DOM_FLAG_BASE_CLOCK_CORE, "core", 2000 }, { nv_clk_src_rop , 0x04 }, { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, { nv_clk_src_vdec , 0x06 }, diff --git a/drm/nouveau/nvkm/subdev/clk/gk104.c b/drm/nouveau/nvkm/subdev/clk/gk104.c index 396f7e4..f194112 100644 --- a/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -485,7 +485,7 @@ gk104_clk = { .domains = { { nv_clk_src_crystal, 0xff }, { nv_clk_src_href , 0xff }, - { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, + { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE | NVKM_CLK_DOM_FLAG_BASE_CLOCK_CORE, "core", 2000 }, { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, { nv_clk_src_mem , 0x03, 0, "memory", 500 }, -- 2.6.3
Thomas Martitz
2015-Dec-24 23:08 UTC
[Nouveau] [RFC PATCH v2 0/7] stabilize kepler reclocking
Hello, first of all, I'm new to this list, so please beer with me. On the other hand, I'm a graduate computer systems engineer with experience in Linux kernel code, so I can hopefully provide useful input/assistance on this topic. I'm replying because I tried your patches on my setup in the hope they'd fix my lockups. Unfortunately they didn't, so I'm offering debug assistance to make my system work as well. Here's my setup: - Arch Linux - Lenovo Thinkpad x230 laptop with integrated intel (ivy bridge) - External GPU (eGPU) connected via ExpressCard <-> PCIe adaptor, a nvidia GeForce 650 Ti (Kepler). The PCIe link is unfortunately limited to Gen 1 and one lane. - PRIME with eGPU as primary (following this guide: https://wiki.archlinux.org/index.php/PRIME#Discrete_Card_as_Primary_GPU) - This setup works fine under Windows 10, and the eGPU gives a lot better performance than the intel chip even with the limited PCIe link. - I compiled nouveau.ko, and nothing else, from your out-of-tree fork (branch stable_reclocking_kepler, HEAD at bc4767c (bios/fan: hardcode the fan mode to linear)) With and without your patches, I get lockups when attempting to reclock to the highest level (echo 0f > /sys/.../pstate) and then running an actual game (Dota 2 in this instance). Reclock as such appears to work fine initially, but the whole system locks up as soon as I start Dota 2. glxgears runs fine. echo 0a > /sys/.../pstate works as wel, however the performance is poor. I suspected that reclocking doesn't work fully in that the core voltage isn't ramped high enough, so that the GPU (and rest of the system) locks up when the load goes above some threshold (glxgears works after all). Unfortunately, I can't see any improvement with your patches. FWIW, I made sure that the self-compiled nouveau.ko is used by running make install and then deleting the distro's shipped nouveau.ko. I verified this by running modprobe -nv nouveau (it also shows that pstate=1 is correctly passed to it). The nouveau.ko (.ko.gz actually) is placed under /lib/modules/4.3.3-2-ARCH/extra/nouveau.ko.gz. Thanks for your ongoing effort to improve the situation on nvidia cards. I hope I can be of any help. Best regards.
Thomas Martitz
2015-Dec-25 07:18 UTC
[Nouveau] [RFC PATCH v2 0/7] stabilize kepler reclocking
Hello, following up on myself, it was suggested on IRC that I better attach a dmesg output. Here's the output of a clean boot & echo 0f > /sys/.../pstate cycle. I can't spot a message that relates to the reclock action, and there's only one weird "nouveau 0000:04:00.0: clk: base: 7 MHz, boost: 7 MHz" message. On the other hand: # cat /sys/bus/pci/devices/0000:04:00.0/pstate 07: core 324 MHz memory 648 MHz 0a: core 549 MHz memory 1620 MHz 0f: core 1032 MHz memory 5400 MHz AC DC * DC: core 1032 MHz memory 5400 MHz One additional data point: In a gnome3 session it can lock up even without starting a game, just by entering the gnome menu (I think the gnome desktop is hardware accelerated). Hope that helps. Best regards
Thomas Martitz
2015-Dec-30 22:42 UTC
[Nouveau] [RFC PATCH v2 0/7] stabilize kepler reclocking
Am 25.12.2015 um 19:37 schrieb Karol Herbst:> Hi Thomas, > > thanks for trying the branch out. Could you please send me your vbios? > > You can get it through installing envytools and nvagetbios or inside > /sys/kernel/debug/dri/*/vbios.rom > > The lookups can actually happen due to undervolting, my branch just fix the > issue that nouveau doesn't reclock at all. > But fixes related to that are already in discussion and will need some time to > actually land.Probably expected, but there was more than one vbios.rom file. Each is 167KB big. I attached all of them. The filenames are derived from the location inside debugfs. # ls /sys/kernel/debug/dri/*/vbios.rom /sys/kernel/debug/dri/1/vbios.rom /sys/kernel/debug/dri/129/vbios.rom/sys/kernel/debug/dri/65/vbios.rom Best regards. -------------- next part -------------- A non-text attachment was scrubbed... Name: vbios-files.tar.7z Type: application/x-7z-compressed Size: 122863 bytes Desc: not available URL: <http://lists.freedesktop.org/archives/nouveau/attachments/20151230/dea563fb/attachment-0001.7z>
Ilia Mirkin
2015-Dec-31 19:47 UTC
[Nouveau] [RFC PATCH v2 0/7] stabilize kepler reclocking
On Wed, Dec 30, 2015 at 5:42 PM, Thomas Martitz <kugel at rockbox.org> wrote:> Am 25.12.2015 um 19:37 schrieb Karol Herbst: >> >> Hi Thomas, >> >> thanks for trying the branch out. Could you please send me your vbios? >> >> You can get it through installing envytools and nvagetbios or inside >> /sys/kernel/debug/dri/*/vbios.rom >> >> The lookups can actually happen due to undervolting, my branch just fix >> the >> issue that nouveau doesn't reclock at all. >> But fixes related to that are already in discussion and will need some >> time to >> actually land. > > > Probably expected, but there was more than one vbios.rom file. Each is 167KB > big. I attached all of them. > > The filenames are derived from the location inside debugfs. > > # ls /sys/kernel/debug/dri/*/vbios.rom > /sys/kernel/debug/dri/1/vbios.rom > /sys/kernel/debug/dri/129/vbios.rom/sys/kernel/debug/dri/65/vbios.romI believe that's just an artifact of how the debugfs stuff is hooked up -- it's a single vbios. But multiple DRI nodes, so multiple debugfs entries. All 3 should be bit-for-bit identical. -ilia