This series addresses various issues inside the reclocking code: 1. after resume the set clocks are reset 2. reclocking not possible while GPU is suspended 3. racy reclocking while GPU is suspending and leading to hangs Some of the patches were part of the bigger reclocking series I sent months ago, some things have changed though. This is also preparation work of changing the clock state due to temperature changes, dynamic reclocking and thermal/policy throttling. v2: remove commits to support partial reclocks v3: don't temper with runpm in nvkm, but move it into sysfs and reorder subdevs Karol Herbst (8): clk: Rename nvkm_pstate_calc to nvkm_clk_update and export it clk: Remove dstate clk: Make pstate a pointer to nvkm_pstate clk: Hold information about the current cstate status clk: We should pass the pstate id around not the index in the list clk: Set clocks to pre suspend state after suspend core/device: Move therm behind clk debugfs: Wake up GPU before doing any reclocking drm/nouveau/include/nvkm/core/device.h | 2 +- drm/nouveau/include/nvkm/subdev/clk.h | 9 +- drm/nouveau/nouveau_debugfs.c | 10 +- drm/nouveau/nvkm/engine/device/ctrl.c | 5 +- drm/nouveau/nvkm/subdev/clk/base.c | 163 +++++++++++++++++++-------------- drm/nouveau/nvkm/subdev/pmu/gk20a.c | 18 ++-- 6 files changed, 117 insertions(+), 90 deletions(-) -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 1/8] clk: Rename nvkm_pstate_calc to nvkm_clk_update and export it
This function will be used to update the current clock state. This will happen for various reasons: * Temperature changes * User changes clocking state * Load changes v2: remove parameter name Signed-off-by: Karol Herbst <karolherbst at gmail.com> --- drm/nouveau/include/nvkm/subdev/clk.h | 1 + drm/nouveau/nvkm/subdev/clk/base.c | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index e5275f74..ce3bbcfe 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -123,6 +123,7 @@ int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature); +int nvkm_clk_update(struct nvkm_clk *, bool wait); int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **); int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **); diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index e4c8d310..ecff3ff3 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -296,7 +296,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) } static void -nvkm_pstate_work(struct work_struct *work) +nvkm_clk_update_work(struct work_struct *work) { struct nvkm_clk *clk = container_of(work, typeof(*clk), work); struct nvkm_subdev *subdev = &clk->subdev; @@ -332,9 +332,15 @@ nvkm_pstate_work(struct work_struct *work) nvkm_notify_get(&clk->pwrsrc_ntfy); } -static int -nvkm_pstate_calc(struct nvkm_clk *clk, bool wait) +int +nvkm_clk_update(struct nvkm_clk *clk, bool wait) { + if (!clk) + return -EINVAL; + + if (!clk->allow_reclock) + return -ENODEV; + atomic_set(&clk->waiting, 1); schedule_work(&clk->work); if (wait) @@ -524,7 +530,7 @@ nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr) if (ret >= 0) { if (ret -= 2, pwr) clk->ustate_ac = ret; else clk->ustate_dc = ret; - return nvkm_pstate_calc(clk, true); + return nvkm_clk_update(clk, true); } return ret; } @@ -536,7 +542,7 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait) if ( rel) clk->astate += rel; clk->astate = min(clk->astate, clk->state_nr - 1); clk->astate = max(clk->astate, 0); - return nvkm_pstate_calc(clk, wait); + return nvkm_clk_update(clk, wait); } int @@ -545,7 +551,7 @@ nvkm_clk_tstate(struct nvkm_clk *clk, u8 temp) if (clk->temp == temp) return 0; clk->temp = temp; - return nvkm_pstate_calc(clk, false); + return nvkm_clk_update(clk, false); } int @@ -555,7 +561,7 @@ nvkm_clk_dstate(struct nvkm_clk *clk, int req, int rel) if ( rel) clk->dstate += rel; clk->dstate = min(clk->dstate, clk->state_nr - 1); clk->dstate = max(clk->dstate, 0); - return nvkm_pstate_calc(clk, true); + return nvkm_clk_update(clk, true); } static int @@ -563,7 +569,7 @@ nvkm_clk_pwrsrc(struct nvkm_notify *notify) { struct nvkm_clk *clk container_of(notify, typeof(*clk), pwrsrc_ntfy); - nvkm_pstate_calc(clk, false); + nvkm_clk_update(clk, false); return NVKM_NOTIFY_DROP; } @@ -618,7 +624,7 @@ nvkm_clk_init(struct nvkm_subdev *subdev) clk->dstate = 0; clk->pstate = -1; clk->temp = 90; /* reasonable default value */ - nvkm_pstate_calc(clk, true); + nvkm_clk_update(clk, true); return 0; } @@ -675,7 +681,7 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, clk->ustate_dc = -1; clk->allow_reclock = allow_reclock; - INIT_WORK(&clk->work, nvkm_pstate_work); + INIT_WORK(&clk->work, nvkm_clk_update_work); init_waitqueue_head(&clk->wait); atomic_set(&clk->waiting, 0); -- 2.14.1
We won't need it now, because we will adjust the clocks depending on engine loads later on anyway or a static lookup table. It also simplifies the clocking logic. This code was nowhere used anyway and just a mock up. v2: fixed typo in commit message Signed-off-by: Karol Herbst <karolherbst at gmail.com> Reviewed-by: Martin Peres <martin.peres at free.fr> --- drm/nouveau/include/nvkm/subdev/clk.h | 2 -- drm/nouveau/nvkm/subdev/clk/base.c | 16 ++-------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index ce3bbcfe..1340f5b8 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -99,7 +99,6 @@ struct nvkm_clk { int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ int astate; /* perfmon adjustment (base) */ - int dstate; /* display adjustment (min+) */ u8 temp; bool allow_reclock; @@ -121,7 +120,6 @@ struct nvkm_clk { int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src); int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); -int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature); int nvkm_clk_update(struct nvkm_clk *, bool wait); diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index ecff3ff3..07d530ed 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -306,15 +306,14 @@ nvkm_clk_update_work(struct work_struct *work) return; clk->pwrsrc = power_supply_is_system_supplied(); - nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C D %d\n", + nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C\n", clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, - clk->astate, clk->temp, clk->dstate); + clk->astate, clk->temp); pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { pstate = (pstate < 0) ? clk->astate : pstate; pstate = min(pstate, clk->state_nr - 1); - pstate = max(pstate, clk->dstate); } else { pstate = clk->pstate = -1; } @@ -554,16 +553,6 @@ nvkm_clk_tstate(struct nvkm_clk *clk, u8 temp) return nvkm_clk_update(clk, false); } -int -nvkm_clk_dstate(struct nvkm_clk *clk, int req, int rel) -{ - if (!rel) clk->dstate = req; - if ( rel) clk->dstate += rel; - clk->dstate = min(clk->dstate, clk->state_nr - 1); - clk->dstate = max(clk->dstate, 0); - return nvkm_clk_update(clk, true); -} - static int nvkm_clk_pwrsrc(struct nvkm_notify *notify) { @@ -621,7 +610,6 @@ nvkm_clk_init(struct nvkm_subdev *subdev) return clk->func->init(clk); clk->astate = clk->state_nr - 1; - clk->dstate = 0; clk->pstate = -1; clk->temp = 90; /* reasonable default value */ nvkm_clk_update(clk, true); -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 3/8] clk: Make pstate a pointer to nvkm_pstate
We will access the current cstate at least every second and this saves us some CPU cycles looking them up every second. v2: Rewording commit message. Signed-off-by: Karol Herbst <karolherbst at gmail.com> Reviewed-by: Martin Peres <martin.peres at free.fr> --- drm/nouveau/include/nvkm/subdev/clk.h | 4 +++- drm/nouveau/nvkm/engine/device/ctrl.c | 5 ++++- drm/nouveau/nvkm/subdev/clk/base.c | 17 ++++++++++++----- drm/nouveau/nvkm/subdev/pmu/gk20a.c | 18 +++++++----------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index 1340f5b8..ec537e08 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -10,6 +10,8 @@ struct nvkm_pll_vals; #define NVKM_CLK_CSTATE_BASE -2 /* pstate base */ #define NVKM_CLK_CSTATE_HIGHEST -3 /* highest possible */ +#define NVKM_CLK_PSTATE_DEFAULT -1 + enum nv_clk_src { nv_clk_src_crystal, nv_clk_src_href, @@ -95,7 +97,7 @@ struct nvkm_clk { struct nvkm_notify pwrsrc_ntfy; int pwrsrc; - int pstate; /* current */ + struct nvkm_pstate *pstate; /* current */ int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ int astate; /* perfmon adjustment (base) */ diff --git a/drm/nouveau/nvkm/engine/device/ctrl.c b/drm/nouveau/nvkm/engine/device/ctrl.c index b0ece71a..da70626c 100644 --- a/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drm/nouveau/nvkm/engine/device/ctrl.c @@ -52,7 +52,10 @@ nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size) args->v0.ustate_ac = clk->ustate_ac; args->v0.ustate_dc = clk->ustate_dc; args->v0.pwrsrc = clk->pwrsrc; - args->v0.pstate = clk->pstate; + if (clk->pstate) + args->v0.pstate = clk->pstate->pstate; + else + args->v0.pstate = NVKM_CLK_PSTATE_DEFAULT; } else { args->v0.count = 0; args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE; diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index 07d530ed..0d4d9fdf 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -271,13 +271,16 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) struct nvkm_pstate *pstate; int ret, idx = 0; + if (pstatei == NVKM_CLK_PSTATE_DEFAULT) + return 0; + list_for_each_entry(pstate, &clk->states, head) { if (idx++ == pstatei) break; } nvkm_debug(subdev, "setting performance state %d\n", pstatei); - clk->pstate = pstatei; + clk->pstate = pstate; nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width); @@ -306,8 +309,12 @@ nvkm_clk_update_work(struct work_struct *work) return; clk->pwrsrc = power_supply_is_system_supplied(); + if (clk->pstate) + pstate = clk->pstate->pstate; + else + pstate = NVKM_CLK_PSTATE_DEFAULT; nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C\n", - clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, + pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, clk->astate, clk->temp); pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; @@ -315,11 +322,11 @@ nvkm_clk_update_work(struct work_struct *work) pstate = (pstate < 0) ? clk->astate : pstate; pstate = min(pstate, clk->state_nr - 1); } else { - pstate = clk->pstate = -1; + pstate = NVKM_CLK_PSTATE_DEFAULT; } nvkm_trace(subdev, "-> %d\n", pstate); - if (pstate != clk->pstate) { + if (!clk->pstate || pstate != clk->pstate->pstate) { int ret = nvkm_pstate_prog(clk, pstate); if (ret) { nvkm_error(subdev, "error setting pstate %d: %d\n", @@ -610,7 +617,7 @@ nvkm_clk_init(struct nvkm_subdev *subdev) return clk->func->init(clk); clk->astate = clk->state_nr - 1; - clk->pstate = -1; + clk->pstate = NULL; clk->temp = 90; /* reasonable default value */ nvkm_clk_update(clk, true); return 0; diff --git a/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 05e81855..de579726 100644 --- a/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -55,24 +55,22 @@ gk20a_pmu_dvfs_target(struct gk20a_pmu *pmu, int *state) return nvkm_clk_astate(clk, *state, 0, false); } -static void -gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu *pmu, int *state) -{ - struct nvkm_clk *clk = pmu->base.subdev.device->clk; - - *state = clk->pstate; -} - static int gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu *pmu, int *state, int load) { struct gk20a_pmu_dvfs_data *data = pmu->data; struct nvkm_clk *clk = pmu->base.subdev.device->clk; + struct nvkm_pstate *pstate = clk->pstate; int cur_level, level; + if (!pstate) { + *state = 0; + return 1; + } + /* For GK20A, the performance level is directly mapped to pstate */ - level = cur_level = clk->pstate; + level = cur_level = clk->pstate->pstate; if (load > data->p_load_max) { level = min(clk->state_nr - 1, level + (clk->state_nr / 3)); @@ -142,8 +140,6 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) nvkm_trace(subdev, "utilization = %d %%, avg_load = %d %%\n", utilization, data->avg_load); - gk20a_pmu_dvfs_get_cur_state(pmu, &state); - if (gk20a_pmu_dvfs_get_target_state(pmu, &state, data->avg_load)) { nvkm_trace(subdev, "set new state to %d\n", state); gk20a_pmu_dvfs_target(pmu, &state); -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 4/8] clk: Hold information about the current cstate status
Later we will have situations where the expected and the current state isn't the same. Signed-off-by: Karol Herbst <karolherbst at gmail.com> Reviewed-by: Martin Peres <martin.peres at free.fr> --- drm/nouveau/include/nvkm/subdev/clk.h | 2 ++ drm/nouveau/nvkm/subdev/clk/base.c | 32 +++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drm/nouveau/include/nvkm/subdev/clk.h b/drm/nouveau/include/nvkm/subdev/clk.h index ec537e08..f35518c3 100644 --- a/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drm/nouveau/include/nvkm/subdev/clk.h @@ -101,6 +101,8 @@ struct nvkm_clk { int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ int astate; /* perfmon adjustment (base) */ + struct nvkm_cstate *cstate; + int exp_cstateid; u8 temp; bool allow_reclock; diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index 0d4d9fdf..d37c13b7 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -146,9 +146,14 @@ static struct nvkm_cstate * nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { struct nvkm_cstate *cstate; - if (cstatei == NVKM_CLK_CSTATE_HIGHEST) + switch (cstatei) { + case NVKM_CLK_CSTATE_HIGHEST: return list_last_entry(&pstate->list, typeof(*cstate), head); - else { + case NVKM_CLK_CSTATE_BASE: + return &pstate->base; + case NVKM_CLK_CSTATE_DEFAULT: + return NULL; + default: list_for_each_entry(cstate, &pstate->list, head) { if (cstate->id == cstatei) return cstate; @@ -167,6 +172,9 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) struct nvkm_cstate *cstate; int ret; + if (cstatei == NVKM_CLK_CSTATE_DEFAULT) + return 0; + if (!list_empty(&pstate->list)) { cstate = nvkm_cstate_get(clk, pstate, cstatei); cstate = nvkm_cstate_find_best(clk, pstate, cstate); @@ -193,6 +201,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) ret = clk->func->calc(clk, cstate); if (ret == 0) { + clk->cstate = cstate; ret = clk->func->prog(clk); clk->func->tidy(clk); } @@ -295,7 +304,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) ram->func->tidy(ram); } - return nvkm_cstate_prog(clk, pstate, NVKM_CLK_CSTATE_HIGHEST); + return nvkm_cstate_prog(clk, pstate, clk->exp_cstateid); } static void @@ -313,9 +322,9 @@ nvkm_clk_update_work(struct work_struct *work) pstate = clk->pstate->pstate; else pstate = NVKM_CLK_PSTATE_DEFAULT; - nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C\n", + nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d C %d T %d°C\n", pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, - clk->astate, clk->temp); + clk->astate, clk->exp_cstateid, clk->temp); pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { @@ -536,6 +545,7 @@ nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr) if (ret >= 0) { if (ret -= 2, pwr) clk->ustate_ac = ret; else clk->ustate_dc = ret; + clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; return nvkm_clk_update(clk, true); } return ret; @@ -548,6 +558,7 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait) if ( rel) clk->astate += rel; clk->astate = min(clk->astate, clk->state_nr - 1); clk->astate = max(clk->astate, 0); + clk->exp_cstateid = NVKM_CLK_CSTATE_BASE; return nvkm_clk_update(clk, wait); } @@ -618,6 +629,8 @@ nvkm_clk_init(struct nvkm_subdev *subdev) clk->astate = clk->state_nr - 1; clk->pstate = NULL; + clk->exp_cstateid = NVKM_CLK_CSTATE_DEFAULT; + clk->cstate = NULL; clk->temp = 90; /* reasonable default value */ nvkm_clk_update(clk, true); return 0; @@ -701,15 +714,20 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, if (mode) { clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen); clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); + clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; } mode = nvkm_stropt(device->cfgopt, "NvClkModeAC", &arglen); - if (mode) + if (mode) { clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen); + clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; + } mode = nvkm_stropt(device->cfgopt, "NvClkModeDC", &arglen); - if (mode) + if (mode) { clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); + clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; + } clk->boost_mode = nvkm_longopt(device->cfgopt, "NvBoost", NVKM_CLK_BOOST_NONE); -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 5/8] clk: We should pass the pstate id around not the index in the list
This makes the code easier, because we can compare the id with pstate->pstate and saves us from the trouble of iterating over the pstates to match the index. v2: reword commit message Signed-off-by: Karol Herbst <karolherbst at gmail.com> Reviewed-by: Martin Peres <martin.peres at free.fr> --- drm/nouveau/nouveau_debugfs.c | 6 +-- drm/nouveau/nvkm/subdev/clk/base.c | 78 +++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/drm/nouveau/nouveau_debugfs.c b/drm/nouveau/nouveau_debugfs.c index 963a4dba..27281c4e 100644 --- a/drm/nouveau/nouveau_debugfs.c +++ b/drm/nouveau/nouveau_debugfs.c @@ -96,11 +96,11 @@ nouveau_debugfs_pstate_get(struct seq_file *m, void *data) } while (attr.index); if (state >= 0) { - if (info.ustate_ac == state) + if (info.ustate_ac == attr.state) seq_printf(m, " AC"); - if (info.ustate_dc == state) + if (info.ustate_dc == attr.state) seq_printf(m, " DC"); - if (info.pstate == state) + if (info.pstate == attr.state) seq_printf(m, " *"); } else { if (info.ustate_ac < -1) diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index d37c13b7..1d71bf09 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -272,23 +272,26 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) * P-States *****************************************************************************/ static int -nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) +nvkm_pstate_prog(struct nvkm_clk *clk, int pstateid) { struct nvkm_subdev *subdev = &clk->subdev; struct nvkm_fb *fb = subdev->device->fb; struct nvkm_pci *pci = subdev->device->pci; struct nvkm_pstate *pstate; - int ret, idx = 0; + int ret; - if (pstatei == NVKM_CLK_PSTATE_DEFAULT) + if (pstateid == NVKM_CLK_PSTATE_DEFAULT) return 0; list_for_each_entry(pstate, &clk->states, head) { - if (idx++ == pstatei) + if (pstate->pstate == pstateid) break; } - nvkm_debug(subdev, "setting performance state %d\n", pstatei); + if (!pstate) + return -EINVAL; + + nvkm_debug(subdev, "setting performance state %x\n", pstateid); clk->pstate = pstate; nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width); @@ -329,7 +332,6 @@ nvkm_clk_update_work(struct work_struct *work) pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { pstate = (pstate < 0) ? clk->astate : pstate; - pstate = min(pstate, clk->state_nr - 1); } else { pstate = NVKM_CLK_PSTATE_DEFAULT; } @@ -490,33 +492,10 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx) /****************************************************************************** * Adjustment triggers *****************************************************************************/ -static int -nvkm_clk_ustate_update(struct nvkm_clk *clk, int req) -{ - struct nvkm_pstate *pstate; - int i = 0; - - if (!clk->allow_reclock) - return -ENOSYS; - - if (req != -1 && req != -2) { - list_for_each_entry(pstate, &clk->states, head) { - if (pstate->pstate == req) - break; - i++; - } - - if (pstate->pstate != req) - return -EINVAL; - req = i; - } - - return req + 2; -} - static int nvkm_clk_nstate(struct nvkm_clk *clk, const char *mode, int arglen) { + struct nvkm_pstate *pstate; int ret = 1; if (clk->allow_reclock && !strncasecmpz(mode, "auto", arglen)) @@ -528,27 +507,46 @@ nvkm_clk_nstate(struct nvkm_clk *clk, const char *mode, int arglen) ((char *)mode)[arglen] = '\0'; if (!kstrtol(mode, 0, &v)) { - ret = nvkm_clk_ustate_update(clk, v); + ret = v; if (ret < 0) ret = 1; } ((char *)mode)[arglen] = save; } - return ret - 2; + if (ret < 0) + return ret; + + list_for_each_entry(pstate, &clk->states, head) { + if (pstate->pstate == ret) + return ret; + } + return -EINVAL; } int nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr) { - int ret = nvkm_clk_ustate_update(clk, req); - if (ret >= 0) { - if (ret -= 2, pwr) clk->ustate_ac = ret; - else clk->ustate_dc = ret; - clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; - return nvkm_clk_update(clk, true); + struct nvkm_pstate *pstate; + bool valid = false; + + list_for_each_entry(pstate, &clk->states, head) { + if (pstate->pstate == req) { + valid = true; + break; + } } - return ret; + + if (!valid) + return -EINVAL; + + if (pwr) + clk->ustate_ac = req; + else + clk->ustate_dc = req; + + clk->exp_cstateid = NVKM_CLK_CSTATE_HIGHEST; + return nvkm_clk_update(clk, true); } int @@ -627,7 +625,7 @@ nvkm_clk_init(struct nvkm_subdev *subdev) if (clk->func->init) return clk->func->init(clk); - clk->astate = clk->state_nr - 1; + clk->astate = NVKM_CLK_PSTATE_DEFAULT; clk->pstate = NULL; clk->exp_cstateid = NVKM_CLK_CSTATE_DEFAULT; clk->cstate = NULL; -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 6/8] clk: Set clocks to pre suspend state after suspend
The idea is to clear out the saved state, because after a resume we can't know what the GPU is clocked to. The reclock is triggered by the call to nvkm_clk_update later in nvkm_clk_init. v2: convert to C style comments Signed-off-by: Karol Herbst <karolherbst at gmail.com> Reviewed-by: Martin Peres <martin.peres at free.fr> --- drm/nouveau/nvkm/subdev/clk/base.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drm/nouveau/nvkm/subdev/clk/base.c b/drm/nouveau/nvkm/subdev/clk/base.c index 1d71bf09..54188d2b 100644 --- a/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drm/nouveau/nvkm/subdev/clk/base.c @@ -625,11 +625,10 @@ nvkm_clk_init(struct nvkm_subdev *subdev) if (clk->func->init) return clk->func->init(clk); - clk->astate = NVKM_CLK_PSTATE_DEFAULT; + /* after a resume we have no idea what clocks are set, reset the state + */ clk->pstate = NULL; - clk->exp_cstateid = NVKM_CLK_CSTATE_DEFAULT; clk->cstate = NULL; - clk->temp = 90; /* reasonable default value */ nvkm_clk_update(clk, true); return 0; } @@ -683,8 +682,13 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, clk->func = func; INIT_LIST_HEAD(&clk->states); clk->domains = func->domains; + + clk->astate = NVKM_CLK_PSTATE_DEFAULT; clk->ustate_ac = -1; clk->ustate_dc = -1; + clk->exp_cstateid = NVKM_CLK_CSTATE_DEFAULT; + clk->temp = 90; /* reasonable default value */ + clk->allow_reclock = allow_reclock; INIT_WORK(&clk->work, nvkm_clk_update_work); -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 7/8] core/device: Move therm behind clk
Later therm will depend on clk reporting new temperatures and triggereing reclocks for thermal throttling or therm related voltage/clock adjustments. Signed-off-by: Karol Herbst <karolherbst at gmail.com> --- drm/nouveau/include/nvkm/core/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drm/nouveau/include/nvkm/core/device.h b/drm/nouveau/include/nvkm/core/device.h index bb4c214f..44a99c3c 100644 --- a/drm/nouveau/include/nvkm/core/device.h +++ b/drm/nouveau/include/nvkm/core/device.h @@ -24,8 +24,8 @@ enum nvkm_devidx { NVKM_SUBDEV_PMU, NVKM_SUBDEV_VOLT, NVKM_SUBDEV_ICCSENSE, - NVKM_SUBDEV_THERM, NVKM_SUBDEV_CLK, + NVKM_SUBDEV_THERM, NVKM_SUBDEV_SECBOOT, NVKM_ENGINE_BSP, -- 2.14.1
Karol Herbst
2017-Sep-03 12:11 UTC
[Nouveau] [PATCH 8/8] debugfs: Wake up GPU before doing any reclocking
Fixes various reclocking related issues on prime systems Signed-off-by: Karol Herbst <karolherbst at gmail.com> --- drm/nouveau/nouveau_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drm/nouveau/nouveau_debugfs.c b/drm/nouveau/nouveau_debugfs.c index 27281c4e..b0a598f9 100644 --- a/drm/nouveau/nouveau_debugfs.c +++ b/drm/nouveau/nouveau_debugfs.c @@ -160,7 +160,11 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, args.ustate = value; } + ret = pm_runtime_get_sync(drm->dev); + if (IS_ERR_VALUE(ret) && ret != -EACCES) + return ret; ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args)); + pm_runtime_put_autosuspend(drm->dev); if (ret < 0) return ret; -- 2.14.1