diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2014-05-27 09:49:45 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:09:58 -0400 |
commit | cd9f8553ad1e6e03e8a3a70cb8d08edd3513fb66 (patch) | |
tree | e934093697d0d849d1068aa4cb41653c521af6f7 /drivers/gpu | |
parent | 3f7be93dab3ccb5f1cfc2a65013ff8fefaa5bbbd (diff) |
gpu: nvgpu: sysfs to put gpu into idle
- Add a sysfs "force_idle" to forcibly idle the GPU
- read on this sysfs will return the current status
0 : not in idle (running)
1 : in forced idle state
"echo 1 > force_idle" will force the gpu into idle
"echo 0 > force_idle" will cause the gpu to resume
Bug 1376916
Bug 1487804
Change-Id: I48dfd52e0d14561220bc4baea0776d1bdfaa7ea5
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | 52 |
2 files changed, 53 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 115cd7f4..6d3c8225 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -248,6 +248,7 @@ struct gk20a { | |||
248 | bool elcg_enabled; | 248 | bool elcg_enabled; |
249 | bool elpg_enabled; | 249 | bool elpg_enabled; |
250 | bool aelpg_enabled; | 250 | bool aelpg_enabled; |
251 | bool forced_idle; | ||
251 | 252 | ||
252 | #ifdef CONFIG_DEBUG_FS | 253 | #ifdef CONFIG_DEBUG_FS |
253 | spinlock_t debugfs_lock; | 254 | spinlock_t debugfs_lock; |
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c index 9ebc5bab..a9e7274e 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/fb.h> | 24 | #include <linux/fb.h> |
25 | #include <linux/gk20a.h> | ||
25 | 26 | ||
26 | #include <mach/clk.h> | 27 | #include <mach/clk.h> |
27 | 28 | ||
@@ -331,6 +332,55 @@ static ssize_t elpg_enable_read(struct device *device, | |||
331 | 332 | ||
332 | static DEVICE_ATTR(elpg_enable, ROOTRW, elpg_enable_read, elpg_enable_store); | 333 | static DEVICE_ATTR(elpg_enable, ROOTRW, elpg_enable_read, elpg_enable_store); |
333 | 334 | ||
335 | static ssize_t force_idle_store(struct device *device, | ||
336 | struct device_attribute *attr, const char *buf, size_t count) | ||
337 | { | ||
338 | struct platform_device *ndev = to_platform_device(device); | ||
339 | struct gk20a *g = get_gk20a(ndev); | ||
340 | unsigned long val = 0; | ||
341 | int err = 0; | ||
342 | |||
343 | if (kstrtoul(buf, 10, &val) < 0) | ||
344 | return -EINVAL; | ||
345 | |||
346 | if (val) { | ||
347 | if (g->forced_idle) | ||
348 | return count; /* do nothing */ | ||
349 | else { | ||
350 | err = gk20a_do_idle(); | ||
351 | if (!err) { | ||
352 | g->forced_idle = 1; | ||
353 | dev_info(device, "gpu is idle : %d\n", | ||
354 | g->forced_idle); | ||
355 | } | ||
356 | } | ||
357 | } else { | ||
358 | if (!g->forced_idle) | ||
359 | return count; /* do nothing */ | ||
360 | else { | ||
361 | err = gk20a_do_unidle(); | ||
362 | if (!err) { | ||
363 | g->forced_idle = 0; | ||
364 | dev_info(device, "gpu is idle : %d\n", | ||
365 | g->forced_idle); | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | |||
370 | return count; | ||
371 | } | ||
372 | |||
373 | static ssize_t force_idle_read(struct device *device, | ||
374 | struct device_attribute *attr, char *buf) | ||
375 | { | ||
376 | struct platform_device *ndev = to_platform_device(device); | ||
377 | struct gk20a *g = get_gk20a(ndev); | ||
378 | |||
379 | return sprintf(buf, "%d\n", g->forced_idle ? 1 : 0); | ||
380 | } | ||
381 | |||
382 | static DEVICE_ATTR(force_idle, ROOTRW, force_idle_read, force_idle_store); | ||
383 | |||
334 | void gk20a_remove_sysfs(struct device *dev) | 384 | void gk20a_remove_sysfs(struct device *dev) |
335 | { | 385 | { |
336 | struct gk20a *g = get_gk20a(to_platform_device(dev)); | 386 | struct gk20a *g = get_gk20a(to_platform_device(dev)); |
@@ -345,6 +395,7 @@ void gk20a_remove_sysfs(struct device *dev) | |||
345 | device_remove_file(dev, &dev_attr_load); | 395 | device_remove_file(dev, &dev_attr_load); |
346 | device_remove_file(dev, &dev_attr_railgate_delay); | 396 | device_remove_file(dev, &dev_attr_railgate_delay); |
347 | device_remove_file(dev, &dev_attr_clockgate_delay); | 397 | device_remove_file(dev, &dev_attr_clockgate_delay); |
398 | device_remove_file(dev, &dev_attr_force_idle); | ||
348 | 399 | ||
349 | if (g->host1x_dev && (dev->parent != &g->host1x_dev->dev)) | 400 | if (g->host1x_dev && (dev->parent != &g->host1x_dev->dev)) |
350 | sysfs_remove_link(&dev->kobj, dev_name(dev)); | 401 | sysfs_remove_link(&dev->kobj, dev_name(dev)); |
@@ -365,6 +416,7 @@ void gk20a_create_sysfs(struct platform_device *dev) | |||
365 | error |= device_create_file(&dev->dev, &dev_attr_load); | 416 | error |= device_create_file(&dev->dev, &dev_attr_load); |
366 | error |= device_create_file(&dev->dev, &dev_attr_railgate_delay); | 417 | error |= device_create_file(&dev->dev, &dev_attr_railgate_delay); |
367 | error |= device_create_file(&dev->dev, &dev_attr_clockgate_delay); | 418 | error |= device_create_file(&dev->dev, &dev_attr_clockgate_delay); |
419 | error |= device_create_file(&dev->dev, &dev_attr_force_idle); | ||
368 | 420 | ||
369 | if (g->host1x_dev && (dev->dev.parent != &g->host1x_dev->dev)) | 421 | if (g->host1x_dev && (dev->dev.parent != &g->host1x_dev->dev)) |
370 | error |= sysfs_create_link(&g->host1x_dev->dev.kobj, | 422 | error |= sysfs_create_link(&g->host1x_dev->dev.kobj, |