diff options
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | 127 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | 4 |
2 files changed, 107 insertions, 24 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c index 234255ce..bd7546b3 100644 --- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/debugfs.h> | 26 | #include <linux/debugfs.h> |
27 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
28 | #include <linux/uaccess.h> | ||
28 | 29 | ||
29 | #include "gk20a.h" | 30 | #include "gk20a.h" |
30 | #include "hw_mc_gk20a.h" | 31 | #include "hw_mc_gk20a.h" |
@@ -1507,6 +1508,8 @@ static void gk20a_save_pmu_sw_state(struct pmu_gk20a *pmu, | |||
1507 | save->pg_buf = pmu->pg_buf; | 1508 | save->pg_buf = pmu->pg_buf; |
1508 | save->sw_ready = pmu->sw_ready; | 1509 | save->sw_ready = pmu->sw_ready; |
1509 | save->pg_init = pmu->pg_init; | 1510 | save->pg_init = pmu->pg_init; |
1511 | save->perfmon_events_cnt = pmu->perfmon_events_cnt; | ||
1512 | save->perfmon_sampling_enabled = pmu->perfmon_sampling_enabled; | ||
1510 | } | 1513 | } |
1511 | 1514 | ||
1512 | static void gk20a_restore_pmu_sw_state(struct pmu_gk20a *pmu, | 1515 | static void gk20a_restore_pmu_sw_state(struct pmu_gk20a *pmu, |
@@ -1524,6 +1527,8 @@ static void gk20a_restore_pmu_sw_state(struct pmu_gk20a *pmu, | |||
1524 | pmu->pg_buf = save->pg_buf; | 1527 | pmu->pg_buf = save->pg_buf; |
1525 | pmu->sw_ready = save->sw_ready; | 1528 | pmu->sw_ready = save->sw_ready; |
1526 | pmu->pg_init = save->pg_init; | 1529 | pmu->pg_init = save->pg_init; |
1530 | pmu->perfmon_events_cnt = save->perfmon_events_cnt; | ||
1531 | pmu->perfmon_sampling_enabled = save->perfmon_sampling_enabled; | ||
1527 | } | 1532 | } |
1528 | 1533 | ||
1529 | void gk20a_remove_pmu_support(struct pmu_gk20a *pmu) | 1534 | void gk20a_remove_pmu_support(struct pmu_gk20a *pmu) |
@@ -1589,6 +1594,9 @@ int gk20a_init_pmu_setup_sw(struct gk20a *g) | |||
1589 | 1594 | ||
1590 | /* TBD: sysmon subtask */ | 1595 | /* TBD: sysmon subtask */ |
1591 | 1596 | ||
1597 | if (IS_ENABLED(CONFIG_TEGRA_GK20A_PERFMON)) | ||
1598 | pmu->perfmon_sampling_enabled = true; | ||
1599 | |||
1592 | pmu->mutex_cnt = pwr_pmu_mutex__size_1_v(); | 1600 | pmu->mutex_cnt = pwr_pmu_mutex__size_1_v(); |
1593 | pmu->mutex = kzalloc(pmu->mutex_cnt * | 1601 | pmu->mutex = kzalloc(pmu->mutex_cnt * |
1594 | sizeof(struct pmu_mutex), GFP_KERNEL); | 1602 | sizeof(struct pmu_mutex), GFP_KERNEL); |
@@ -2556,7 +2564,6 @@ static int pmu_perfmon_start_sampling(struct pmu_gk20a *pmu) | |||
2556 | struct pmu_v *pv = &g->ops.pmu_ver; | 2564 | struct pmu_v *pv = &g->ops.pmu_ver; |
2557 | struct pmu_cmd cmd; | 2565 | struct pmu_cmd cmd; |
2558 | struct pmu_payload payload; | 2566 | struct pmu_payload payload; |
2559 | u32 current_rate = 0; | ||
2560 | u32 seq; | 2567 | u32 seq; |
2561 | 2568 | ||
2562 | /* PERFMON Start */ | 2569 | /* PERFMON Start */ |
@@ -2570,20 +2577,9 @@ static int pmu_perfmon_start_sampling(struct pmu_gk20a *pmu) | |||
2570 | pv->perfmon_start_set_state_id(&cmd.cmd.perfmon, | 2577 | pv->perfmon_start_set_state_id(&cmd.cmd.perfmon, |
2571 | pmu->perfmon_state_id[PMU_DOMAIN_GROUP_PSTATE]); | 2578 | pmu->perfmon_state_id[PMU_DOMAIN_GROUP_PSTATE]); |
2572 | 2579 | ||
2573 | current_rate = rate_gpu_to_gpc2clk(gk20a_clk_get_rate(g)); | ||
2574 | if (current_rate >= gpc_pll_params.max_freq) | ||
2575 | pv->perfmon_start_set_flags(&cmd.cmd.perfmon, | ||
2576 | PMU_PERFMON_FLAG_ENABLE_DECREASE); | ||
2577 | else if (current_rate <= gpc_pll_params.min_freq) | ||
2578 | pv->perfmon_start_set_flags(&cmd.cmd.perfmon, | ||
2579 | PMU_PERFMON_FLAG_ENABLE_INCREASE); | ||
2580 | else | ||
2581 | pv->perfmon_start_set_flags(&cmd.cmd.perfmon, | ||
2582 | PMU_PERFMON_FLAG_ENABLE_INCREASE | | ||
2583 | PMU_PERFMON_FLAG_ENABLE_DECREASE); | ||
2584 | |||
2585 | pv->perfmon_start_set_flags(&cmd.cmd.perfmon, | 2580 | pv->perfmon_start_set_flags(&cmd.cmd.perfmon, |
2586 | pv->perfmon_start_get_flags(&cmd.cmd.perfmon) | | 2581 | PMU_PERFMON_FLAG_ENABLE_INCREASE | |
2582 | PMU_PERFMON_FLAG_ENABLE_DECREASE | | ||
2587 | PMU_PERFMON_FLAG_CLEAR_PREV); | 2583 | PMU_PERFMON_FLAG_CLEAR_PREV); |
2588 | 2584 | ||
2589 | memset(&payload, 0, sizeof(struct pmu_payload)); | 2585 | memset(&payload, 0, sizeof(struct pmu_payload)); |
@@ -2625,9 +2621,6 @@ static int pmu_perfmon_stop_sampling(struct pmu_gk20a *pmu) | |||
2625 | static int pmu_handle_perfmon_event(struct pmu_gk20a *pmu, | 2621 | static int pmu_handle_perfmon_event(struct pmu_gk20a *pmu, |
2626 | struct pmu_perfmon_msg *msg) | 2622 | struct pmu_perfmon_msg *msg) |
2627 | { | 2623 | { |
2628 | struct gk20a *g = pmu->g; | ||
2629 | u32 rate; | ||
2630 | |||
2631 | gk20a_dbg_fn(""); | 2624 | gk20a_dbg_fn(""); |
2632 | 2625 | ||
2633 | switch (msg->msg_type) { | 2626 | switch (msg->msg_type) { |
@@ -2635,17 +2628,13 @@ static int pmu_handle_perfmon_event(struct pmu_gk20a *pmu, | |||
2635 | gk20a_dbg_pmu("perfmon increase event: " | 2628 | gk20a_dbg_pmu("perfmon increase event: " |
2636 | "state_id %d, ground_id %d, pct %d", | 2629 | "state_id %d, ground_id %d, pct %d", |
2637 | msg->gen.state_id, msg->gen.group_id, msg->gen.data); | 2630 | msg->gen.state_id, msg->gen.group_id, msg->gen.data); |
2638 | /* increase gk20a clock freq by 20% */ | 2631 | (pmu->perfmon_events_cnt)++; |
2639 | rate = gk20a_clk_get_rate(g); | ||
2640 | gk20a_clk_set_rate(g, rate * 6 / 5); | ||
2641 | break; | 2632 | break; |
2642 | case PMU_PERFMON_MSG_ID_DECREASE_EVENT: | 2633 | case PMU_PERFMON_MSG_ID_DECREASE_EVENT: |
2643 | gk20a_dbg_pmu("perfmon decrease event: " | 2634 | gk20a_dbg_pmu("perfmon decrease event: " |
2644 | "state_id %d, ground_id %d, pct %d", | 2635 | "state_id %d, ground_id %d, pct %d", |
2645 | msg->gen.state_id, msg->gen.group_id, msg->gen.data); | 2636 | msg->gen.state_id, msg->gen.group_id, msg->gen.data); |
2646 | /* decrease gk20a clock freq by 10% */ | 2637 | (pmu->perfmon_events_cnt)++; |
2647 | rate = gk20a_clk_get_rate(g); | ||
2648 | gk20a_clk_set_rate(g, (rate / 10) * 7); | ||
2649 | break; | 2638 | break; |
2650 | case PMU_PERFMON_MSG_ID_INIT_EVENT: | 2639 | case PMU_PERFMON_MSG_ID_INIT_EVENT: |
2651 | pmu->perfmon_ready = 1; | 2640 | pmu->perfmon_ready = 1; |
@@ -2656,7 +2645,7 @@ static int pmu_handle_perfmon_event(struct pmu_gk20a *pmu, | |||
2656 | } | 2645 | } |
2657 | 2646 | ||
2658 | /* restart sampling */ | 2647 | /* restart sampling */ |
2659 | if (IS_ENABLED(CONFIG_GK20A_PERFMON)) | 2648 | if (pmu->perfmon_sampling_enabled) |
2660 | return pmu_perfmon_start_sampling(pmu); | 2649 | return pmu_perfmon_start_sampling(pmu); |
2661 | return 0; | 2650 | return 0; |
2662 | } | 2651 | } |
@@ -3753,6 +3742,85 @@ static const struct file_operations elpg_transitions_fops = { | |||
3753 | .release = single_release, | 3742 | .release = single_release, |
3754 | }; | 3743 | }; |
3755 | 3744 | ||
3745 | static int perfmon_events_enable_show(struct seq_file *s, void *data) | ||
3746 | { | ||
3747 | struct gk20a *g = s->private; | ||
3748 | |||
3749 | seq_printf(s, "%u\n", g->pmu.perfmon_sampling_enabled ? 1 : 0); | ||
3750 | return 0; | ||
3751 | |||
3752 | } | ||
3753 | |||
3754 | static int perfmon_events_enable_open(struct inode *inode, struct file *file) | ||
3755 | { | ||
3756 | return single_open(file, perfmon_events_enable_show, inode->i_private); | ||
3757 | } | ||
3758 | |||
3759 | static ssize_t perfmon_events_enable_write(struct file *file, | ||
3760 | const char __user *userbuf, size_t count, loff_t *ppos) | ||
3761 | { | ||
3762 | struct seq_file *s = file->private_data; | ||
3763 | struct gk20a *g = s->private; | ||
3764 | unsigned long val = 0; | ||
3765 | char buf[40]; | ||
3766 | int buf_size; | ||
3767 | |||
3768 | memset(buf, 0, sizeof(buf)); | ||
3769 | buf_size = min(count, (sizeof(buf)-1)); | ||
3770 | |||
3771 | if (copy_from_user(buf, userbuf, buf_size)) | ||
3772 | return -EFAULT; | ||
3773 | |||
3774 | if (kstrtoul(buf, 10, &val) < 0) | ||
3775 | return -EINVAL; | ||
3776 | |||
3777 | /* Don't turn on gk20a unnecessarily */ | ||
3778 | if (g->power_on) { | ||
3779 | gk20a_busy(g->dev); | ||
3780 | if (val && !g->pmu.perfmon_sampling_enabled) { | ||
3781 | g->pmu.perfmon_sampling_enabled = true; | ||
3782 | pmu_perfmon_start_sampling(&(g->pmu)); | ||
3783 | } else if (!val && g->pmu.perfmon_sampling_enabled) { | ||
3784 | g->pmu.perfmon_sampling_enabled = false; | ||
3785 | pmu_perfmon_stop_sampling(&(g->pmu)); | ||
3786 | } | ||
3787 | gk20a_idle(g->dev); | ||
3788 | } else { | ||
3789 | g->pmu.perfmon_sampling_enabled = val ? true : false; | ||
3790 | } | ||
3791 | |||
3792 | return count; | ||
3793 | } | ||
3794 | |||
3795 | static const struct file_operations perfmon_events_enable_fops = { | ||
3796 | .open = perfmon_events_enable_open, | ||
3797 | .read = seq_read, | ||
3798 | .write = perfmon_events_enable_write, | ||
3799 | .llseek = seq_lseek, | ||
3800 | .release = single_release, | ||
3801 | }; | ||
3802 | |||
3803 | static int perfmon_events_count_show(struct seq_file *s, void *data) | ||
3804 | { | ||
3805 | struct gk20a *g = s->private; | ||
3806 | |||
3807 | seq_printf(s, "%lu\n", g->pmu.perfmon_events_cnt); | ||
3808 | return 0; | ||
3809 | |||
3810 | } | ||
3811 | |||
3812 | static int perfmon_events_count_open(struct inode *inode, struct file *file) | ||
3813 | { | ||
3814 | return single_open(file, perfmon_events_count_show, inode->i_private); | ||
3815 | } | ||
3816 | |||
3817 | static const struct file_operations perfmon_events_count_fops = { | ||
3818 | .open = perfmon_events_count_open, | ||
3819 | .read = seq_read, | ||
3820 | .llseek = seq_lseek, | ||
3821 | .release = single_release, | ||
3822 | }; | ||
3823 | |||
3756 | int gk20a_pmu_debugfs_init(struct platform_device *dev) | 3824 | int gk20a_pmu_debugfs_init(struct platform_device *dev) |
3757 | { | 3825 | { |
3758 | struct dentry *d; | 3826 | struct dentry *d; |
@@ -3771,6 +3839,17 @@ int gk20a_pmu_debugfs_init(struct platform_device *dev) | |||
3771 | if (!d) | 3839 | if (!d) |
3772 | goto err_out; | 3840 | goto err_out; |
3773 | 3841 | ||
3842 | d = debugfs_create_file( | ||
3843 | "perfmon_events_enable", S_IRUGO, platform->debugfs, g, | ||
3844 | &perfmon_events_enable_fops); | ||
3845 | if (!d) | ||
3846 | goto err_out; | ||
3847 | |||
3848 | d = debugfs_create_file( | ||
3849 | "perfmon_events_count", S_IRUGO, platform->debugfs, g, | ||
3850 | &perfmon_events_count_fops); | ||
3851 | if (!d) | ||
3852 | goto err_out; | ||
3774 | return 0; | 3853 | return 0; |
3775 | 3854 | ||
3776 | err_out: | 3855 | err_out: |
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h index de519bf6..488558fe 100644 --- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | |||
@@ -1049,6 +1049,8 @@ struct pmu_gk20a { | |||
1049 | struct pmu_cmdline_args_v0 args_v0; | 1049 | struct pmu_cmdline_args_v0 args_v0; |
1050 | struct pmu_cmdline_args_v1 args_v1; | 1050 | struct pmu_cmdline_args_v1 args_v1; |
1051 | }; | 1051 | }; |
1052 | unsigned long perfmon_events_cnt; | ||
1053 | bool perfmon_sampling_enabled; | ||
1052 | }; | 1054 | }; |
1053 | 1055 | ||
1054 | struct gk20a_pmu_save_state { | 1056 | struct gk20a_pmu_save_state { |
@@ -1064,6 +1066,8 @@ struct gk20a_pmu_save_state { | |||
1064 | wait_queue_head_t pg_wq; | 1066 | wait_queue_head_t pg_wq; |
1065 | bool sw_ready; | 1067 | bool sw_ready; |
1066 | struct work_struct pg_init; | 1068 | struct work_struct pg_init; |
1069 | unsigned long perfmon_events_cnt; | ||
1070 | bool perfmon_sampling_enabled; | ||
1067 | }; | 1071 | }; |
1068 | 1072 | ||
1069 | int gk20a_init_pmu_support(struct gk20a *g); | 1073 | int gk20a_init_pmu_support(struct gk20a *g); |