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 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 and dynamic reclocking. v2: remove commits to support partial reclocks Karol Herbst (7): 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 clk: Check pm_runtime status before reclocking drm/nouveau/include/nvkm/subdev/clk.h | 9 +- drm/nouveau/nouveau_debugfs.c | 6 +- drm/nouveau/nvkm/engine/device/ctrl.c | 5 +- drm/nouveau/nvkm/subdev/clk/base.c | 175 ++++++++++++++++++++-------------- drm/nouveau/nvkm/subdev/pmu/gk20a.c | 18 ++-- 5 files changed, 123 insertions(+), 90 deletions(-) -- 2.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 1/7] 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.13.2
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.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 3/7] 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 978aae3c..3dd550c3 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.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 4/7] 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.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 5/7] 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 fd64dfdc..b114a429 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;
}
@@ -491,32 +493,9 @@ 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.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 6/7] 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.13.2
Karol Herbst
2017-Jul-01 16:02 UTC
[Nouveau] [PATCH v2 7/7] clk: Check pm_runtime status before reclocking
We don't want to change anything on the GPU if it's suspended. Also we
need to increase the refcount on the pm_runtime counter so that the GPU
won't be suspended while reclocking.
v2: convert to C style comments
Signed-off-by: Karol Herbst <karolherbst at gmail.com>
---
drm/nouveau/nvkm/subdev/clk/base.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drm/nouveau/nvkm/subdev/clk/base.c
b/drm/nouveau/nvkm/subdev/clk/base.c
index 54188d2b..81093e13 100644
--- a/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drm/nouveau/nvkm/subdev/clk/base.c
@@ -315,6 +315,7 @@ nvkm_clk_update_work(struct work_struct *work)
{
struct nvkm_clk *clk = container_of(work, typeof(*clk), work);
struct nvkm_subdev *subdev = &clk->subdev;
+ struct device *dev = subdev->device->dev;
int pstate;
if (!atomic_xchg(&clk->waiting, 0))
@@ -337,8 +338,17 @@ nvkm_clk_update_work(struct work_struct *work)
}
nvkm_trace(subdev, "-> %d\n", pstate);
- if (!clk->pstate || pstate != clk->pstate->pstate) {
- int ret = nvkm_pstate_prog(clk, pstate);
+
+ /* only call into the code if the GPU is powered on */
+ if ((!clk->pstate || pstate != clk->pstate->pstate)
+ && !pm_runtime_suspended(dev)) {
+ int ret;
+ /* it would be a shame if the GPU goes into suspend while doing
+ * the reclock
+ */
+ pm_runtime_get_sync(dev);
+ ret = nvkm_pstate_prog(clk, pstate);
+ pm_runtime_put(dev);
if (ret) {
nvkm_error(subdev, "error setting pstate %d: %d\n",
pstate, ret);
--
2.13.2