diff options
author | Karol Herbst <karolherbst@gmail.com> | 2016-07-16 09:26:25 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2016-10-12 03:29:24 -0400 |
commit | 1f7f3d91ad38afc706f838fb5a642b21d28e4485 (patch) | |
tree | 2e9b734e2d52c66b5d91687416d6d6db2c01fc1e | |
parent | 0d6f81003e9ecc2d6552be92d3d894c916097552 (diff) |
drm/nouveau/clk: Respect voltage limits in nvkm_cstate_prog
We should never allow to select a cstate which current voltage (depending
on the temperature) is higher than
1. the max volt entries in the voltage map table.
2. what tha gpu actually can volt to.
v3: Use find_best for all cstates before actually trying.
Add nvkm_cstate_get function to get cstate by index.
v5: Cstates with voltages lower then min_uv are valid.
Move nvkm_cstate_get into the previous commit.
Signed-off-by: Karol Herbst <karolherbst@gmail.com>
Reviewed-by: Martin Peres <martin.peres@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 52 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | 2 |
3 files changed, 54 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index 6fd933df763e..441f6e7079d2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h | |||
@@ -27,6 +27,7 @@ struct nvkm_volt { | |||
27 | u8 max2_id; | 27 | u8 max2_id; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature); | ||
30 | int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id); | 31 | int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id); |
31 | int nvkm_volt_get(struct nvkm_volt *); | 32 | int nvkm_volt_get(struct nvkm_volt *); |
32 | int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp, | 33 | int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp, |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 688c908908d8..60392b2edcbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | |||
@@ -74,6 +74,57 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, | |||
74 | /****************************************************************************** | 74 | /****************************************************************************** |
75 | * C-States | 75 | * C-States |
76 | *****************************************************************************/ | 76 | *****************************************************************************/ |
77 | static bool | ||
78 | nvkm_cstate_valid(struct nvkm_clk *clk, struct nvkm_cstate *cstate, | ||
79 | u32 max_volt, int temp) | ||
80 | { | ||
81 | struct nvkm_volt *volt = clk->subdev.device->volt; | ||
82 | int voltage; | ||
83 | |||
84 | if (!volt) | ||
85 | return true; | ||
86 | |||
87 | voltage = nvkm_volt_map(volt, cstate->voltage, temp); | ||
88 | if (voltage < 0) | ||
89 | return false; | ||
90 | return voltage <= min(max_volt, volt->max_uv); | ||
91 | } | ||
92 | |||
93 | static struct nvkm_cstate * | ||
94 | nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate, | ||
95 | struct nvkm_cstate *start) | ||
96 | { | ||
97 | struct nvkm_device *device = clk->subdev.device; | ||
98 | struct nvkm_volt *volt = device->volt; | ||
99 | struct nvkm_cstate *cstate; | ||
100 | int max_volt; | ||
101 | |||
102 | if (!pstate || !start) | ||
103 | return NULL; | ||
104 | |||
105 | if (!volt) | ||
106 | return start; | ||
107 | |||
108 | max_volt = volt->max_uv; | ||
109 | if (volt->max0_id != 0xff) | ||
110 | max_volt = min(max_volt, | ||
111 | nvkm_volt_map(volt, volt->max0_id, clk->temp)); | ||
112 | if (volt->max1_id != 0xff) | ||
113 | max_volt = min(max_volt, | ||
114 | nvkm_volt_map(volt, volt->max1_id, clk->temp)); | ||
115 | if (volt->max2_id != 0xff) | ||
116 | max_volt = min(max_volt, | ||
117 | nvkm_volt_map(volt, volt->max2_id, clk->temp)); | ||
118 | |||
119 | for (cstate = start; &cstate->head != &pstate->list; | ||
120 | cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) { | ||
121 | if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp)) | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | return cstate; | ||
126 | } | ||
127 | |||
77 | static struct nvkm_cstate * | 128 | static struct nvkm_cstate * |
78 | nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) | 129 | nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) |
79 | { | 130 | { |
@@ -101,6 +152,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) | |||
101 | 152 | ||
102 | if (!list_empty(&pstate->list)) { | 153 | if (!list_empty(&pstate->list)) { |
103 | cstate = nvkm_cstate_get(clk, pstate, cstatei); | 154 | cstate = nvkm_cstate_get(clk, pstate, cstatei); |
155 | cstate = nvkm_cstate_find_best(clk, pstate, cstate); | ||
104 | } else { | 156 | } else { |
105 | cstate = &pstate->base; | 157 | cstate = &pstate->base; |
106 | } | 158 | } |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 40ba088a5c81..5e07bd3aaccc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | |||
@@ -88,7 +88,7 @@ nvkm_volt_map_min(struct nvkm_volt *volt, u8 id) | |||
88 | return id ? id * 10000 : -ENODEV; | 88 | return id ? id * 10000 : -ENODEV; |
89 | } | 89 | } |
90 | 90 | ||
91 | static int | 91 | int |
92 | nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp) | 92 | nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp) |
93 | { | 93 | { |
94 | struct nvkm_bios *bios = volt->subdev.device->bios; | 94 | struct nvkm_bios *bios = volt->subdev.device->bios; |