aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c139
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h2
4 files changed, 120 insertions, 46 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 531e435d9fb3..009089e093f3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -485,15 +485,27 @@ struct nouveau_pm_tbl_entry {
485 u8 tUNK_20, tUNK_21; 485 u8 tUNK_20, tUNK_21;
486}; 486};
487 487
488struct nouveau_pm_profile;
489struct nouveau_pm_profile_func {
490 struct nouveau_pm_level *(*select)(struct nouveau_pm_profile *);
491};
492
493struct nouveau_pm_profile {
494 const struct nouveau_pm_profile_func *func;
495 struct list_head head;
496 char name[8];
497};
498
488#define NOUVEAU_PM_MAX_LEVEL 8 499#define NOUVEAU_PM_MAX_LEVEL 8
489struct nouveau_pm_level { 500struct nouveau_pm_level {
501 struct nouveau_pm_profile profile;
490 struct device_attribute dev_attr; 502 struct device_attribute dev_attr;
491 char name[32]; 503 char name[32];
492 int id; 504 int id;
493 505
506 struct nouveau_pm_memtiming timing;
494 u32 memory; 507 u32 memory;
495 u16 memscript; 508 u16 memscript;
496 struct nouveau_pm_memtiming timing;
497 509
498 u32 core; 510 u32 core;
499 u32 shader; 511 u32 shader;
@@ -542,6 +554,10 @@ struct nouveau_pm_engine {
542 struct nouveau_pm_threshold_temp threshold_temp; 554 struct nouveau_pm_threshold_temp threshold_temp;
543 struct nouveau_pm_fan fan; 555 struct nouveau_pm_fan fan;
544 556
557 struct nouveau_pm_profile *profile_ac;
558 struct nouveau_pm_profile *profile_dc;
559 struct list_head profiles;
560
545 struct nouveau_pm_level boot; 561 struct nouveau_pm_level boot;
546 struct nouveau_pm_level *cur; 562 struct nouveau_pm_level *cur;
547 563
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index cc8beb8e2f06..e64901509f90 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -394,6 +394,13 @@ nouveau_perf_init(struct drm_device *dev)
394 snprintf(perflvl->name, sizeof(perflvl->name), 394 snprintf(perflvl->name, sizeof(perflvl->name),
395 "performance_level_%d", i); 395 "performance_level_%d", i);
396 perflvl->id = i; 396 perflvl->id = i;
397
398 snprintf(perflvl->profile.name, sizeof(perflvl->profile.name),
399 "%d", perflvl->id);
400 perflvl->profile.func = &nouveau_pm_static_profile_func;
401 list_add_tail(&perflvl->profile.head, &pm->profiles);
402
403
397 pm->nr_perflvl++; 404 pm->nr_perflvl++;
398 } 405 }
399} 406}
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 7c25567fb56a..4fff09e3f592 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -168,51 +168,99 @@ error:
168 return ret; 168 return ret;
169} 169}
170 170
171void
172nouveau_pm_trigger(struct drm_device *dev)
173{
174 struct drm_nouveau_private *dev_priv = dev->dev_private;
175 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
176 struct nouveau_pm_profile *profile = NULL;
177 struct nouveau_pm_level *perflvl = NULL;
178 int ret;
179
180 /* select power profile based on current power source */
181 if (power_supply_is_system_supplied())
182 profile = pm->profile_ac;
183 else
184 profile = pm->profile_dc;
185
186 /* select performance level based on profile */
187 perflvl = profile->func->select(profile);
188
189 /* change perflvl, if necessary */
190 if (perflvl != pm->cur) {
191 struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
192 u64 time0 = ptimer->read(dev);
193
194 NV_INFO(dev, "setting performance level: %d", perflvl->id);
195 ret = nouveau_pm_perflvl_set(dev, perflvl);
196 if (ret)
197 NV_INFO(dev, "> reclocking failed: %d\n\n", ret);
198
199 NV_INFO(dev, "> reclocking took %lluns\n\n",
200 ptimer->read(dev) - time0);
201 }
202}
203
204static struct nouveau_pm_profile *
205profile_find(struct drm_device *dev, const char *string)
206{
207 struct drm_nouveau_private *dev_priv = dev->dev_private;
208 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
209 struct nouveau_pm_profile *profile;
210
211 list_for_each_entry(profile, &pm->profiles, head) {
212 if (!strncmp(profile->name, string, sizeof(profile->name)))
213 return profile;
214 }
215
216 return NULL;
217}
218
171static int 219static int
172nouveau_pm_profile_set(struct drm_device *dev, const char *profile) 220nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
173{ 221{
174 struct drm_nouveau_private *dev_priv = dev->dev_private; 222 struct drm_nouveau_private *dev_priv = dev->dev_private;
175 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 223 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
176 struct nouveau_pm_level *perflvl = NULL; 224 struct nouveau_pm_profile *ac = NULL, *dc = NULL;
177 u64 start_time; 225 char string[16], *cur = string, *ptr;
178 int ret = 0;
179 long pl;
180 226
181 /* safety precaution, for now */ 227 /* safety precaution, for now */
182 if (nouveau_perflvl_wr != 7777) 228 if (nouveau_perflvl_wr != 7777)
183 return -EPERM; 229 return -EPERM;
184 230
185 if (!strncmp(profile, "boot", 4)) 231 strncpy(string, profile, sizeof(string));
186 perflvl = &pm->boot; 232 if ((ptr = strchr(string, '\n')))
187 else { 233 *ptr = '\0';
188 int i;
189 if (kstrtol(profile, 10, &pl) == -EINVAL)
190 return -EINVAL;
191
192 for (i = 0; i < pm->nr_perflvl; i++) {
193 if (pm->perflvl[i].id == pl) {
194 perflvl = &pm->perflvl[i];
195 break;
196 }
197 }
198 234
199 if (!perflvl) 235 ptr = strsep(&cur, ",");
200 return -EINVAL; 236 if (ptr)
201 } 237 ac = profile_find(dev, ptr);
202 238
203 NV_INFO(dev, "setting performance level: %s", profile); 239 ptr = strsep(&cur, ",");
204 start_time = nv04_timer_read(dev); 240 if (ptr)
205 ret = nouveau_pm_perflvl_set(dev, perflvl); 241 dc = profile_find(dev, ptr);
206 if (!ret) { 242 else
207 NV_INFO(dev, "> reclocking took %lluns\n\n", 243 dc = ac;
208 (nv04_timer_read(dev) - start_time));
209 } else {
210 NV_INFO(dev, "> reclocking failed\n\n");
211 }
212 244
213 return ret; 245 if (ac == NULL || dc == NULL)
246 return -EINVAL;
247
248 pm->profile_ac = ac;
249 pm->profile_dc = dc;
250 nouveau_pm_trigger(dev);
251 return 0;
252}
253
254static struct nouveau_pm_level *
255nouveau_pm_static_select(struct nouveau_pm_profile *profile)
256{
257 return container_of(profile, struct nouveau_pm_level, profile);
214} 258}
215 259
260const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
261 .select = nouveau_pm_static_select,
262};
263
216static int 264static int
217nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 265nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
218{ 266{
@@ -273,14 +321,15 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
273 if (perflvl->fanspeed) 321 if (perflvl->fanspeed)
274 snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed); 322 snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
275 323
276 snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f); 324 snprintf(ptr, len, "%s%s%s%s%s\n", c, s, m, v, f);
277} 325}
278 326
279static ssize_t 327static ssize_t
280nouveau_pm_get_perflvl_info(struct device *d, 328nouveau_pm_get_perflvl_info(struct device *d,
281 struct device_attribute *a, char *buf) 329 struct device_attribute *a, char *buf)
282{ 330{
283 struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a; 331 struct nouveau_pm_level *perflvl =
332 container_of(a, struct nouveau_pm_level, dev_attr);
284 char *ptr = buf; 333 char *ptr = buf;
285 int len = PAGE_SIZE; 334 int len = PAGE_SIZE;
286 335
@@ -302,12 +351,8 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
302 int len = PAGE_SIZE, ret; 351 int len = PAGE_SIZE, ret;
303 char *ptr = buf; 352 char *ptr = buf;
304 353
305 if (!pm->cur) 354 snprintf(ptr, len, "profile: %s, %s\nc:",
306 snprintf(ptr, len, "setting: boot\n"); 355 pm->profile_ac->name, pm->profile_dc->name);
307 else if (pm->cur == &pm->boot)
308 snprintf(ptr, len, "setting: boot\nc:");
309 else
310 snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id);
311 ptr += strlen(buf); 356 ptr += strlen(buf);
312 len -= strlen(buf); 357 len -= strlen(buf);
313 358
@@ -776,6 +821,7 @@ nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
776 bool ac = power_supply_is_system_supplied(); 821 bool ac = power_supply_is_system_supplied();
777 822
778 NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); 823 NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC");
824 nouveau_pm_trigger(dev);
779 } 825 }
780 826
781 return NOTIFY_OK; 827 return NOTIFY_OK;
@@ -802,6 +848,14 @@ nouveau_pm_init(struct drm_device *dev)
802 } 848 }
803 849
804 strncpy(pm->boot.name, "boot", 4); 850 strncpy(pm->boot.name, "boot", 4);
851 strncpy(pm->boot.profile.name, "boot", 4);
852 pm->boot.profile.func = &nouveau_pm_static_profile_func;
853
854 INIT_LIST_HEAD(&pm->profiles);
855 list_add(&pm->boot.profile.head, &pm->profiles);
856
857 pm->profile_ac = &pm->boot.profile;
858 pm->profile_dc = &pm->boot.profile;
805 pm->cur = &pm->boot; 859 pm->cur = &pm->boot;
806 860
807 /* add performance levels from vbios */ 861 /* add performance levels from vbios */
@@ -818,13 +872,8 @@ nouveau_pm_init(struct drm_device *dev)
818 NV_INFO(dev, "c:%s", info); 872 NV_INFO(dev, "c:%s", info);
819 873
820 /* switch performance levels now if requested */ 874 /* switch performance levels now if requested */
821 if (nouveau_perflvl != NULL) { 875 if (nouveau_perflvl != NULL)
822 ret = nouveau_pm_profile_set(dev, nouveau_perflvl); 876 nouveau_pm_profile_set(dev, nouveau_perflvl);
823 if (ret) {
824 NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
825 nouveau_perflvl, ret);
826 }
827 }
828 877
829 /* determine the current fan speed */ 878 /* determine the current fan speed */
830 pm->fan.percent = nouveau_pwmfan_get(dev); 879 pm->fan.percent = nouveau_pwmfan_get(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 1a8ae15803a0..3f82dfea61dd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -47,6 +47,8 @@ int nouveau_mem_exec(struct nouveau_mem_exec_func *,
47int nouveau_pm_init(struct drm_device *dev); 47int nouveau_pm_init(struct drm_device *dev);
48void nouveau_pm_fini(struct drm_device *dev); 48void nouveau_pm_fini(struct drm_device *dev);
49void nouveau_pm_resume(struct drm_device *dev); 49void nouveau_pm_resume(struct drm_device *dev);
50extern const struct nouveau_pm_profile_func nouveau_pm_static_profile_func;
51void nouveau_pm_trigger(struct drm_device *dev);
50 52
51/* nouveau_volt.c */ 53/* nouveau_volt.c */
52void nouveau_volt_init(struct drm_device *); 54void nouveau_volt_init(struct drm_device *);