diff options
author | Thomas Fleury <tfleury@nvidia.com> | 2016-09-13 17:25:28 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2016-12-07 18:01:14 -0500 |
commit | 05805ec65b2cd6413c9d0d711d3798fd457fed6e (patch) | |
tree | 8aacb5c36a72f86a183c0f210a2aeeac0c382ae3 /drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | |
parent | 21094783114b9314d57f412196544a34b3a40f4a (diff) |
gpu: nvgpu: ioctls for clock controls
Add ioctls for clock range and VF points query.
Add ioctls to set target mhz, and get actual mhz.
Jira DNVGPU-125
Change-Id: I7639789bb15eabd8c98adc468201dba3a6e19ade
Signed-off-by: Thomas Fleury <tfleury@nvidia.com>
Reviewed-on: http://git-master/r/1223473
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
(cherry picked from commit 5e635ae34221c99a739321bcfc1418db56c1051d)
Reviewed-on: http://git-master/r/1243107
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | 332 |
1 files changed, 329 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c index 56bc2c7a..7d344e9a 100644 --- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/file.h> | 19 | #include <linux/file.h> |
20 | #include <linux/anon_inodes.h> | 20 | #include <linux/anon_inodes.h> |
21 | #include <linux/nvgpu.h> | 21 | #include <linux/nvgpu.h> |
22 | #include <linux/bitops.h> | ||
22 | #include <uapi/linux/nvgpu.h> | 23 | #include <uapi/linux/nvgpu.h> |
23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
24 | 25 | ||
@@ -29,25 +30,55 @@ | |||
29 | #include "hw_gr_gk20a.h" | 30 | #include "hw_gr_gk20a.h" |
30 | #include "hw_fb_gk20a.h" | 31 | #include "hw_fb_gk20a.h" |
31 | #include "hw_timer_gk20a.h" | 32 | #include "hw_timer_gk20a.h" |
33 | #include "clk/clk_arb.h" | ||
34 | |||
35 | |||
36 | struct gk20a_ctrl_priv { | ||
37 | struct device *dev; | ||
38 | struct nvgpu_clk_session *clk_session; | ||
39 | }; | ||
32 | 40 | ||
33 | int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp) | 41 | int gk20a_ctrl_dev_open(struct inode *inode, struct file *filp) |
34 | { | 42 | { |
35 | struct gk20a *g; | 43 | struct gk20a *g; |
44 | struct gk20a_ctrl_priv *priv; | ||
45 | int err; | ||
36 | 46 | ||
37 | gk20a_dbg_fn(""); | 47 | gk20a_dbg_fn(""); |
38 | 48 | ||
39 | g = container_of(inode->i_cdev, | 49 | g = container_of(inode->i_cdev, |
40 | struct gk20a, ctrl.cdev); | 50 | struct gk20a, ctrl.cdev); |
41 | 51 | ||
42 | filp->private_data = g->dev; | 52 | priv = kzalloc(sizeof(struct gk20a_ctrl_priv), GFP_KERNEL); |
53 | if (!priv) | ||
54 | return -ENOMEM; | ||
43 | 55 | ||
44 | return 0; | 56 | filp->private_data = priv; |
57 | priv->dev = g->dev; | ||
58 | |||
59 | if (!g->gr.sw_ready) { | ||
60 | err = gk20a_busy(g->dev); | ||
61 | if (err) | ||
62 | return err; | ||
63 | |||
64 | gk20a_idle(g->dev); | ||
65 | } | ||
66 | |||
67 | return nvgpu_clk_arb_init_session(g, &priv->clk_session); | ||
45 | } | 68 | } |
46 | 69 | ||
47 | int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) | 70 | int gk20a_ctrl_dev_release(struct inode *inode, struct file *filp) |
48 | { | 71 | { |
72 | struct gk20a_ctrl_priv *priv = filp->private_data; | ||
73 | struct gk20a *g = gk20a_from_dev(priv->dev); | ||
74 | struct nvgpu_clk_session *clk_session = priv->clk_session; | ||
75 | |||
49 | gk20a_dbg_fn(""); | 76 | gk20a_dbg_fn(""); |
50 | 77 | ||
78 | if (clk_session) | ||
79 | nvgpu_clk_arb_cleanup_session(g, clk_session); | ||
80 | kfree(priv); | ||
81 | |||
51 | return 0; | 82 | return 0; |
52 | } | 83 | } |
53 | 84 | ||
@@ -789,9 +820,284 @@ static int nvgpu_gpu_get_memory_state(struct gk20a *g, | |||
789 | return err; | 820 | return err; |
790 | } | 821 | } |
791 | 822 | ||
823 | static int nvgpu_gpu_clk_get_vf_points(struct gk20a *g, | ||
824 | struct gk20a_ctrl_priv *priv, | ||
825 | struct nvgpu_gpu_clk_vf_points_args *args) | ||
826 | { | ||
827 | struct nvgpu_gpu_clk_vf_point clk_point; | ||
828 | struct nvgpu_gpu_clk_vf_point __user *entry; | ||
829 | struct nvgpu_clk_session *session = priv->clk_session; | ||
830 | u32 clk_domains = 0; | ||
831 | int err; | ||
832 | u16 last_mhz; | ||
833 | u16 *fpoints; | ||
834 | u32 i; | ||
835 | u32 max_points = 0; | ||
836 | u32 num_points = 0; | ||
837 | u16 min_mhz; | ||
838 | u16 max_mhz; | ||
839 | |||
840 | gk20a_dbg_fn(""); | ||
841 | |||
842 | if (!session || args->flags) | ||
843 | return -EINVAL; | ||
844 | |||
845 | clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); | ||
846 | args->num_entries = 0; | ||
847 | |||
848 | if ((args->clk_domain & clk_domains) == 0) | ||
849 | return -EINVAL; | ||
850 | |||
851 | err = nvgpu_clk_arb_get_arbiter_clk_f_points(g, | ||
852 | args->clk_domain, &max_points, NULL); | ||
853 | if (err) | ||
854 | return err; | ||
855 | |||
856 | if (!args->max_entries) { | ||
857 | args->max_entries = max_points; | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | if (args->max_entries < max_points) | ||
862 | return -EINVAL; | ||
863 | |||
864 | err = nvgpu_clk_arb_get_arbiter_clk_range(g, args->clk_domain, | ||
865 | &min_mhz, &max_mhz); | ||
866 | if (err) | ||
867 | return err; | ||
868 | |||
869 | fpoints = kcalloc(max_points, sizeof(u16), GFP_KERNEL); | ||
870 | if (!fpoints) | ||
871 | return -ENOMEM; | ||
872 | |||
873 | err = nvgpu_clk_arb_get_arbiter_clk_f_points(g, | ||
874 | args->clk_domain, &max_points, fpoints); | ||
875 | if (err) | ||
876 | goto fail; | ||
877 | |||
878 | entry = (struct nvgpu_gpu_clk_vf_point __user *) | ||
879 | (uintptr_t)args->clk_vf_point_entries; | ||
880 | |||
881 | last_mhz = 0; | ||
882 | num_points = 0; | ||
883 | for (i = 0; (i < max_points) && !err; i++) { | ||
884 | |||
885 | /* filter out duplicate frequencies */ | ||
886 | if (fpoints[i] == last_mhz) | ||
887 | continue; | ||
888 | |||
889 | /* filter out out-of-range frequencies */ | ||
890 | if ((fpoints[i] < min_mhz) || (fpoints[i] > max_mhz)) | ||
891 | continue; | ||
892 | |||
893 | last_mhz = fpoints[i]; | ||
894 | clk_point.freq_mhz = fpoints[i]; | ||
895 | |||
896 | err = copy_to_user((void __user *)entry, &clk_point, | ||
897 | sizeof(clk_point)); | ||
898 | |||
899 | num_points++; | ||
900 | entry++; | ||
901 | } | ||
902 | |||
903 | args->num_entries = num_points; | ||
904 | |||
905 | fail: | ||
906 | kfree(fpoints); | ||
907 | return err; | ||
908 | } | ||
909 | |||
910 | static int nvgpu_gpu_clk_get_range(struct gk20a *g, | ||
911 | struct gk20a_ctrl_priv *priv, | ||
912 | struct nvgpu_gpu_clk_range_args *args) | ||
913 | { | ||
914 | struct nvgpu_gpu_clk_range clk_range; | ||
915 | struct nvgpu_gpu_clk_range __user *entry; | ||
916 | struct nvgpu_clk_session *session = priv->clk_session; | ||
917 | |||
918 | u32 clk_domains = 0; | ||
919 | u32 num_domains; | ||
920 | int bit; | ||
921 | u16 min_mhz, max_mhz; | ||
922 | int err; | ||
923 | |||
924 | gk20a_dbg_fn(""); | ||
925 | |||
926 | if (!session || args->flags) | ||
927 | return -EINVAL; | ||
928 | |||
929 | args->num_entries = 0; | ||
930 | |||
931 | clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); | ||
932 | num_domains = hweight_long(clk_domains); | ||
933 | |||
934 | if (!args->max_entries) { | ||
935 | args->max_entries = num_domains; | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | if (args->max_entries < num_domains) | ||
940 | return -EINVAL; | ||
941 | |||
942 | entry = (struct nvgpu_gpu_clk_range __user *) | ||
943 | (uintptr_t)args->clk_range_entries; | ||
944 | |||
945 | memset(&clk_range, 0, sizeof(clk_range)); | ||
946 | |||
947 | while (clk_domains) { | ||
948 | bit = ffs(clk_domains) - 1; | ||
949 | |||
950 | clk_range.clk_domain = BIT(bit); | ||
951 | |||
952 | err = nvgpu_clk_arb_get_arbiter_clk_range(g, | ||
953 | clk_range.clk_domain, &min_mhz, &max_mhz); | ||
954 | if (err) | ||
955 | return err; | ||
956 | |||
957 | clk_range.min_mhz = min_mhz; | ||
958 | clk_range.max_mhz = max_mhz; | ||
959 | |||
960 | err = copy_to_user(entry, &clk_range, sizeof(clk_range)); | ||
961 | if (err) | ||
962 | return -EFAULT; | ||
963 | |||
964 | entry++; | ||
965 | clk_domains &= ~BIT(bit); | ||
966 | } | ||
967 | |||
968 | args->num_entries = num_domains; | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | |||
974 | static int nvgpu_gpu_clk_set_info(struct gk20a *g, | ||
975 | struct gk20a_ctrl_priv *priv, | ||
976 | struct nvgpu_gpu_clk_set_info_args *args) | ||
977 | { | ||
978 | struct nvgpu_gpu_clk_info clk_info; | ||
979 | struct nvgpu_gpu_clk_info __user *entry; | ||
980 | struct nvgpu_clk_session *session = priv->clk_session; | ||
981 | u32 clk_domains = 0; | ||
982 | u32 i; | ||
983 | int fd; | ||
984 | |||
985 | gk20a_dbg_fn(""); | ||
986 | |||
987 | if (!session || args->flags) | ||
988 | return -EINVAL; | ||
989 | |||
990 | clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); | ||
991 | if (!clk_domains) | ||
992 | return -EINVAL; | ||
993 | |||
994 | fd = nvgpu_clk_arb_install_session_fd(g, session); | ||
995 | if (fd < 0) | ||
996 | return fd; | ||
997 | |||
998 | entry = (struct nvgpu_gpu_clk_info __user *) | ||
999 | (uintptr_t)args->clk_info_entries; | ||
1000 | |||
1001 | for (i = 0; i < args->num_entries; i++, entry++) { | ||
1002 | |||
1003 | if (copy_from_user(&clk_info, entry, sizeof(clk_info))) | ||
1004 | return -EFAULT; | ||
1005 | |||
1006 | if ((clk_info.clk_domain & clk_domains) != clk_info.clk_domain) | ||
1007 | return -EINVAL; | ||
1008 | |||
1009 | if (hweight_long(clk_info.clk_domain) != 1) | ||
1010 | return -EINVAL; | ||
1011 | } | ||
1012 | |||
1013 | entry = (struct nvgpu_gpu_clk_info __user *) | ||
1014 | (uintptr_t)args->clk_info_entries; | ||
1015 | |||
1016 | for (i = 0; i < args->num_entries; i++, entry++) { | ||
1017 | |||
1018 | if (copy_from_user(&clk_info, (void __user *)entry, | ||
1019 | sizeof(clk_info))) | ||
1020 | return -EFAULT; | ||
1021 | |||
1022 | nvgpu_clk_arb_set_session_target_mhz(session, | ||
1023 | clk_info.clk_domain, clk_info.target_mhz); | ||
1024 | } | ||
1025 | |||
1026 | nvgpu_clk_arb_apply_session_constraints(g, session); | ||
1027 | |||
1028 | args->req_nr = nvgpu_clk_arb_get_session_req_nr(g, session); | ||
1029 | args->fd = fd; | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | static int nvgpu_gpu_clk_get_info(struct gk20a *g, | ||
1036 | struct gk20a_ctrl_priv *priv, | ||
1037 | struct nvgpu_gpu_clk_get_info_args *args) | ||
1038 | { | ||
1039 | struct nvgpu_gpu_clk_info clk_info; | ||
1040 | struct nvgpu_gpu_clk_info __user *entry; | ||
1041 | struct nvgpu_clk_session *session = priv->clk_session; | ||
1042 | u32 clk_domains = 0; | ||
1043 | u32 num_domains; | ||
1044 | u16 actual_mhz; | ||
1045 | u16 target_mhz; | ||
1046 | int err; | ||
1047 | u32 i; | ||
1048 | |||
1049 | gk20a_dbg_fn(""); | ||
1050 | |||
1051 | if (!session || args->flags) | ||
1052 | return -EINVAL; | ||
1053 | |||
1054 | clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); | ||
1055 | if (!clk_domains) | ||
1056 | return -EINVAL; | ||
1057 | |||
1058 | args->last_req_nr = nvgpu_clk_arb_get_arbiter_req_nr(g); | ||
1059 | |||
1060 | num_domains = hweight_long(clk_domains); | ||
1061 | if (!args->num_entries) { | ||
1062 | args->num_entries = num_domains; | ||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | entry = (struct nvgpu_gpu_clk_info __user *) | ||
1067 | (uintptr_t)args->clk_info_entries; | ||
1068 | |||
1069 | for (i = 0; i < args->num_entries; i++, entry++) { | ||
1070 | |||
1071 | if (copy_from_user(&clk_info, (void __user *)entry, | ||
1072 | sizeof(clk_info))) | ||
1073 | return -EFAULT; | ||
1074 | |||
1075 | err = nvgpu_clk_arb_get_arbiter_actual_mhz(g, | ||
1076 | clk_info.clk_domain, &actual_mhz); | ||
1077 | if (err) | ||
1078 | return err; | ||
1079 | |||
1080 | err = nvgpu_clk_arb_get_session_target_mhz(session, | ||
1081 | clk_info.clk_domain, &target_mhz); | ||
1082 | if (err) | ||
1083 | return err; | ||
1084 | |||
1085 | clk_info.actual_mhz = actual_mhz; | ||
1086 | clk_info.target_mhz = target_mhz; | ||
1087 | |||
1088 | err = copy_to_user((void __user *)entry, &clk_info, | ||
1089 | sizeof(clk_info)); | ||
1090 | if (err) | ||
1091 | return -EFAULT; | ||
1092 | } | ||
1093 | |||
1094 | return 0; | ||
1095 | } | ||
1096 | |||
792 | long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 1097 | long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
793 | { | 1098 | { |
794 | struct device *dev = filp->private_data; | 1099 | struct gk20a_ctrl_priv *priv = filp->private_data; |
1100 | struct device *dev = priv->dev; | ||
795 | struct gk20a *g = get_gk20a(dev); | 1101 | struct gk20a *g = get_gk20a(dev); |
796 | struct nvgpu_gpu_zcull_get_ctx_size_args *get_ctx_size_args; | 1102 | struct nvgpu_gpu_zcull_get_ctx_size_args *get_ctx_size_args; |
797 | struct nvgpu_gpu_zcull_get_info_args *get_info_args; | 1103 | struct nvgpu_gpu_zcull_get_info_args *get_info_args; |
@@ -1050,6 +1356,26 @@ long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg | |||
1050 | (struct nvgpu_gpu_get_memory_state_args *)buf); | 1356 | (struct nvgpu_gpu_get_memory_state_args *)buf); |
1051 | break; | 1357 | break; |
1052 | 1358 | ||
1359 | case NVGPU_GPU_IOCTL_CLK_GET_RANGE: | ||
1360 | err = nvgpu_gpu_clk_get_range(g, priv, | ||
1361 | (struct nvgpu_gpu_clk_range_args *)buf); | ||
1362 | break; | ||
1363 | |||
1364 | case NVGPU_GPU_IOCTL_CLK_GET_VF_POINTS: | ||
1365 | err = nvgpu_gpu_clk_get_vf_points(g, priv, | ||
1366 | (struct nvgpu_gpu_clk_vf_points_args *)buf); | ||
1367 | break; | ||
1368 | |||
1369 | case NVGPU_GPU_IOCTL_CLK_SET_INFO: | ||
1370 | err = nvgpu_gpu_clk_set_info(g, priv, | ||
1371 | (struct nvgpu_gpu_clk_set_info_args *)buf); | ||
1372 | break; | ||
1373 | |||
1374 | case NVGPU_GPU_IOCTL_CLK_GET_INFO: | ||
1375 | err = nvgpu_gpu_clk_get_info(g, priv, | ||
1376 | (struct nvgpu_gpu_clk_get_info_args *)buf); | ||
1377 | break; | ||
1378 | |||
1053 | default: | 1379 | default: |
1054 | dev_dbg(dev_from_gk20a(g), "unrecognized gpu ioctl cmd: 0x%x", cmd); | 1380 | dev_dbg(dev_from_gk20a(g), "unrecognized gpu ioctl cmd: 0x%x", cmd); |
1055 | err = -ENOTTY; | 1381 | err = -ENOTTY; |