diff options
-rw-r--r-- | drivers/gpu/nvgpu/vgpu/vgpu.c | 62 | ||||
-rw-r--r-- | include/linux/tegra_vgpu.h | 6 |
2 files changed, 68 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c index c28130f2..dc7c4320 100644 --- a/drivers/gpu/nvgpu/vgpu/vgpu.c +++ b/drivers/gpu/nvgpu/vgpu/vgpu.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
20 | #include <linux/pm_qos.h> | ||
21 | |||
20 | #include "vgpu/vgpu.h" | 22 | #include "vgpu/vgpu.h" |
21 | #include "vgpu/fecs_trace_vgpu.h" | 23 | #include "vgpu/fecs_trace_vgpu.h" |
22 | #include "gk20a/debug_gk20a.h" | 24 | #include "gk20a/debug_gk20a.h" |
@@ -24,6 +26,7 @@ | |||
24 | #include "gk20a/hw_mc_gk20a.h" | 26 | #include "gk20a/hw_mc_gk20a.h" |
25 | #include "gk20a/ctxsw_trace_gk20a.h" | 27 | #include "gk20a/ctxsw_trace_gk20a.h" |
26 | #include "gk20a/tsg_gk20a.h" | 28 | #include "gk20a/tsg_gk20a.h" |
29 | #include "gk20a/gk20a_scale.h" | ||
27 | #include "gk20a/channel_gk20a.h" | 30 | #include "gk20a/channel_gk20a.h" |
28 | #include "gm20b/hal_gm20b.h" | 31 | #include "gm20b/hal_gm20b.h" |
29 | 32 | ||
@@ -430,6 +433,61 @@ done: | |||
430 | return err; | 433 | return err; |
431 | } | 434 | } |
432 | 435 | ||
436 | static int vgpu_qos_notify(struct notifier_block *nb, | ||
437 | unsigned long n, void *data) | ||
438 | { | ||
439 | struct gk20a_scale_profile *profile = | ||
440 | container_of(nb, struct gk20a_scale_profile, | ||
441 | qos_notify_block); | ||
442 | struct gk20a_platform *platform = gk20a_get_platform(profile->dev); | ||
443 | struct tegra_vgpu_cmd_msg msg = {}; | ||
444 | struct tegra_vgpu_gpu_clk_rate_params *p = &msg.params.gpu_clk_rate; | ||
445 | u32 max_freq; | ||
446 | int err; | ||
447 | |||
448 | gk20a_dbg_fn(""); | ||
449 | |||
450 | max_freq = (u32)pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS); | ||
451 | |||
452 | msg.cmd = TEGRA_VGPU_CMD_SET_GPU_CLK_RATE; | ||
453 | msg.handle = platform->virt_handle; | ||
454 | p->rate = max_freq; | ||
455 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | ||
456 | err = err ? err : msg.ret; | ||
457 | if (err) | ||
458 | gk20a_err(profile->dev, "%s failed, err=%d", __func__, err); | ||
459 | |||
460 | return NOTIFY_OK; /* need notify call further */ | ||
461 | } | ||
462 | |||
463 | static int vgpu_pm_qos_init(struct device *dev) | ||
464 | { | ||
465 | struct gk20a *g = get_gk20a(dev); | ||
466 | struct gk20a_scale_profile *profile; | ||
467 | |||
468 | profile = kzalloc(sizeof(*profile), GFP_KERNEL); | ||
469 | if (!profile) | ||
470 | return -ENOMEM; | ||
471 | |||
472 | profile->dev = dev; | ||
473 | profile->qos_notify_block.notifier_call = vgpu_qos_notify; | ||
474 | g->scale_profile = profile; | ||
475 | pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS, | ||
476 | &profile->qos_notify_block); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void vgpu_pm_qos_remove(struct device *dev) | ||
482 | { | ||
483 | struct gk20a *g = get_gk20a(dev); | ||
484 | |||
485 | pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS, | ||
486 | &g->scale_profile->qos_notify_block); | ||
487 | kfree(g->scale_profile); | ||
488 | g->scale_profile = NULL; | ||
489 | } | ||
490 | |||
433 | static int vgpu_pm_init(struct device *dev) | 491 | static int vgpu_pm_init(struct device *dev) |
434 | { | 492 | { |
435 | int err = 0; | 493 | int err = 0; |
@@ -437,6 +495,9 @@ static int vgpu_pm_init(struct device *dev) | |||
437 | gk20a_dbg_fn(""); | 495 | gk20a_dbg_fn(""); |
438 | 496 | ||
439 | __pm_runtime_disable(dev, false); | 497 | __pm_runtime_disable(dev, false); |
498 | err = vgpu_pm_qos_init(dev); | ||
499 | if (err) | ||
500 | return err; | ||
440 | 501 | ||
441 | return err; | 502 | return err; |
442 | } | 503 | } |
@@ -534,6 +595,7 @@ int vgpu_remove(struct platform_device *pdev) | |||
534 | struct gk20a *g = get_gk20a(dev); | 595 | struct gk20a *g = get_gk20a(dev); |
535 | gk20a_dbg_fn(""); | 596 | gk20a_dbg_fn(""); |
536 | 597 | ||
598 | vgpu_pm_qos_remove(dev); | ||
537 | if (g->remove_support) | 599 | if (g->remove_support) |
538 | g->remove_support(dev); | 600 | g->remove_support(dev); |
539 | 601 | ||
diff --git a/include/linux/tegra_vgpu.h b/include/linux/tegra_vgpu.h index 6e8f5d53..c821f31a 100644 --- a/include/linux/tegra_vgpu.h +++ b/include/linux/tegra_vgpu.h | |||
@@ -97,6 +97,7 @@ enum { | |||
97 | TEGRA_VGPU_CMD_CHANNEL_ENABLE = 58, | 97 | TEGRA_VGPU_CMD_CHANNEL_ENABLE = 58, |
98 | TEGRA_VGPU_CMD_READ_PTIMER = 59, | 98 | TEGRA_VGPU_CMD_READ_PTIMER = 59, |
99 | TEGRA_VGPU_CMD_SET_POWERGATE = 60, | 99 | TEGRA_VGPU_CMD_SET_POWERGATE = 60, |
100 | TEGRA_VGPU_CMD_SET_GPU_CLK_RATE = 61, | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | struct tegra_vgpu_connect_params { | 103 | struct tegra_vgpu_connect_params { |
@@ -399,6 +400,10 @@ struct tegra_vgpu_set_powergate_params { | |||
399 | u32 mode; | 400 | u32 mode; |
400 | }; | 401 | }; |
401 | 402 | ||
403 | struct tegra_vgpu_gpu_clk_rate_params { | ||
404 | u32 rate; /* in kHz */ | ||
405 | }; | ||
406 | |||
402 | struct tegra_vgpu_cmd_msg { | 407 | struct tegra_vgpu_cmd_msg { |
403 | u32 cmd; | 408 | u32 cmd; |
404 | int ret; | 409 | int ret; |
@@ -441,6 +446,7 @@ struct tegra_vgpu_cmd_msg { | |||
441 | struct tegra_vgpu_tsg_runlist_interleave_params tsg_interleave; | 446 | struct tegra_vgpu_tsg_runlist_interleave_params tsg_interleave; |
442 | struct tegra_vgpu_read_ptimer_params read_ptimer; | 447 | struct tegra_vgpu_read_ptimer_params read_ptimer; |
443 | struct tegra_vgpu_set_powergate_params set_powergate; | 448 | struct tegra_vgpu_set_powergate_params set_powergate; |
449 | struct tegra_vgpu_gpu_clk_rate_params gpu_clk_rate; | ||
444 | char padding[192]; | 450 | char padding[192]; |
445 | } params; | 451 | } params; |
446 | }; | 452 | }; |