diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c index 7d344e9ad..8e243eab8 100644 --- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c @@ -917,37 +917,51 @@ static int nvgpu_gpu_clk_get_range(struct gk20a *g, u32 clk_domains = 0; u32 num_domains; + u32 i; int bit; u16 min_mhz, max_mhz; int err; gk20a_dbg_fn(""); - if (!session || args->flags) + if (!session) return -EINVAL; - args->num_entries = 0; + if (!args->flags) { + clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); + num_domains = hweight_long(clk_domains); - clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); - num_domains = hweight_long(clk_domains); + if (!args->num_entries) { + args->num_entries = num_domains; + return 0; + } - if (!args->max_entries) { - args->max_entries = num_domains; - return 0; + if (args->num_entries < num_domains) + return -EINVAL; + + args->num_entries = 0; + + } else { + if (args->flags != NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS) + return -EINVAL; + + num_domains = args->num_entries; } - if (args->max_entries < num_domains) - return -EINVAL; - entry = (struct nvgpu_gpu_clk_range __user *) (uintptr_t)args->clk_range_entries; - memset(&clk_range, 0, sizeof(clk_range)); + for (i = 0; i < num_domains; i++, entry++) { - while (clk_domains) { - bit = ffs(clk_domains) - 1; - - clk_range.clk_domain = BIT(bit); + if (args->flags == NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS) { + if (copy_from_user(&clk_range, (void __user *)entry, + sizeof(clk_range))) + return -EFAULT; + } else { + bit = ffs(clk_domains) - 1; + clk_range.clk_domain = BIT(bit); + clk_domains &= ~BIT(bit); + } err = nvgpu_clk_arb_get_arbiter_clk_range(g, clk_range.clk_domain, &min_mhz, &max_mhz); @@ -956,13 +970,11 @@ static int nvgpu_gpu_clk_get_range(struct gk20a *g, clk_range.min_mhz = min_mhz; clk_range.max_mhz = max_mhz; + clk_range.flags = 0; err = copy_to_user(entry, &clk_range, sizeof(clk_range)); if (err) return -EFAULT; - - entry++; - clk_domains &= ~BIT(bit); } args->num_entries = num_domains; @@ -1043,34 +1055,52 @@ static int nvgpu_gpu_clk_get_info(struct gk20a *g, u32 num_domains; u16 actual_mhz; u16 target_mhz; - int err; u32 i; + int err; + int bit; gk20a_dbg_fn(""); - if (!session || args->flags) - return -EINVAL; - - clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); - if (!clk_domains) + if (!session) return -EINVAL; args->last_req_nr = nvgpu_clk_arb_get_arbiter_req_nr(g); - num_domains = hweight_long(clk_domains); - if (!args->num_entries) { - args->num_entries = num_domains; - return 0; + if (!args->flags) { + clk_domains = nvgpu_clk_arb_get_arbiter_clk_domains(g); + num_domains = hweight_long(clk_domains); + + if (!args->num_entries) { + args->num_entries = num_domains; + return 0; + } + + if (args->num_entries < num_domains) + return -EINVAL; + + args->num_entries = 0; + + } else { + if (args->flags != NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS) + return -EINVAL; + + num_domains = args->num_entries; } entry = (struct nvgpu_gpu_clk_info __user *) (uintptr_t)args->clk_info_entries; - for (i = 0; i < args->num_entries; i++, entry++) { + for (i = 0; i < num_domains; i++, entry++) { - if (copy_from_user(&clk_info, (void __user *)entry, - sizeof(clk_info))) - return -EFAULT; + if (args->flags == NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS) { + if (copy_from_user(&clk_info, (void __user *)entry, + sizeof(clk_info))) + return -EFAULT; + } else { + bit = ffs(clk_domains) - 1; + clk_info.clk_domain = BIT(bit); + clk_domains &= ~BIT(bit); + } err = nvgpu_clk_arb_get_arbiter_actual_mhz(g, clk_info.clk_domain, &actual_mhz); @@ -1084,6 +1114,7 @@ static int nvgpu_gpu_clk_get_info(struct gk20a *g, clk_info.actual_mhz = actual_mhz; clk_info.target_mhz = target_mhz; + clk_info.flags = 0; err = copy_to_user((void __user *)entry, &clk_info, sizeof(clk_info)); @@ -1091,6 +1122,8 @@ static int nvgpu_gpu_clk_get_info(struct gk20a *g, return -EFAULT; } + args->num_entries = num_domains; + return 0; } diff --git a/include/uapi/linux/nvgpu.h b/include/uapi/linux/nvgpu.h index d45820363..2d044db44 100644 --- a/include/uapi/linux/nvgpu.h +++ b/include/uapi/linux/nvgpu.h @@ -524,20 +524,24 @@ struct nvgpu_gpu_clk_range { __u32 max_mhz; }; +/* Request on specific clock domains */ +#define NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS (1UL << 0) + struct nvgpu_gpu_clk_range_args { - /* Flags (not currently used) */ + /* Flags. If NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS the request will + apply only to domains specified in clock entries. In this case + caller must set clock domain in each entry. Otherwise, the + ioctl will return all clock domains. + */ __u32 flags; - /* in/out: max number of entries in clk_range_entries buffer. If zero, - NVGPU_GPU_IOCTL_CLK_GET_RANGE will return 0 and max_entries will be - set to the max number of clock domains. If there are more entries - than max_entries, then ioctl will return -EINVAL. - */ - __u16 max_entries; + __u16 pad0; - /* out: number of nvgpu_gpu_clk_range entries contained in - clk_range_entries */ + /* in/out: Number of entries in clk_range_entries buffer. If zero, + NVGPU_GPU_IOCTL_CLK_GET_RANGE will return 0 and + num_entries will be set to number of clock domains. + */ __u16 num_entries; /* in: Pointer to clock range entries in the caller's address space. @@ -606,14 +610,18 @@ struct nvgpu_gpu_clk_info { struct nvgpu_gpu_clk_get_info_args { - /* in: Flags (not currently used). */ + /* Flags. If NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS the request will + apply only to domains specified in clock entries. In this case + caller must set clock domain in each entry. Otherwise, the + ioctl will return all clock domains. + */ __u32 flags; __u16 pad0; /* in/out: Number of clock info entries contained in clk_info_entries. If zero, NVGPU_GPU_IOCTL_CLK_GET_INFO will return 0 and - max_entries will be set to number of clock domains. Also, + num_entries will be set to number of clock domains. Also, last_req_nr will be updated, which allows checking if a given request has completed. If there are more entries than max_entries, then ioctl will return -EINVAL. @@ -623,8 +631,9 @@ struct nvgpu_gpu_clk_get_info_args { /* in: Pointer to nvgpu_gpu_clk_info entries in the caller's address space. Buffer size must be at least: num_entries * sizeof(struct nvgpu_gpu_clk_info) - For each entry, the clk_domain to be queried should be set. Note - that clk_info_entries passed to an NVGPU_GPU_IOCTL_CLK_SET_INFO, + If NVGPU_GPU_CLK_FLAG_SPECIFIC_DOMAINS is set, caller should set + clk_domain to be queried in each entry. With this flag, + clk_info_entries passed to an NVGPU_GPU_IOCTL_CLK_SET_INFO, can be re-used on completion for a NVGPU_GPU_IOCTL_CLK_GET_INFO. This allows checking actual_mhz. */