From 6b35cb05b7822174bf037da7229154004df4f229 Mon Sep 17 00:00:00 2001 From: Sami Kiminki Date: Tue, 12 Apr 2016 22:33:36 +0300 Subject: gpu: nvgpu: Implement NVGPU_GPU_IOCTL_GET_GPU_TIME Implement NVGPU_GPU_IOCTL_GET_GPU_TIME for reading the GPU time. Bug 1395833 Change-Id: I7ddc7c28ff0c9a336cc0dcd820b15fb0fea714d0 Signed-off-by: Sami Kiminki Reviewed-on: http://git-master/r/1125630 Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c | 57 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/nvgpu.h | 13 +++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c index b1d35141..56b4d947 100644 --- a/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/ctrl_gk20a.c @@ -622,6 +622,58 @@ static int nvgpu_gpu_get_cpu_time_correlation_info( return err; } +static int nvgpu_gpu_get_gpu_time( + struct gk20a *g, + struct nvgpu_gpu_get_gpu_time_args *args) +{ + int err = 0; + const unsigned int max_iterations = 3; + unsigned int i = 0; + u32 gpu_timestamp_hi_prev = 0; + + err = gk20a_busy(g->dev); + if (err) + return err; + + /* Note. The GPU nanosecond timer consists of two 32-bit + * registers (high & low). To detect a possible low register + * wrap-around between the reads, we need to read the high + * register before and after low. The wraparound happens + * approximately once per 4 secs. */ + + /* get initial gpu_timestamp_hi value */ + gpu_timestamp_hi_prev = gk20a_readl(g, timer_time_1_r()); + + for (i = 0; i < max_iterations; ++i) { + u32 gpu_timestamp_hi = 0; + u32 gpu_timestamp_lo = 0; + + rmb(); /* maintain read order */ + gpu_timestamp_lo = gk20a_readl(g, timer_time_0_r()); + rmb(); /* maintain read order */ + gpu_timestamp_hi = gk20a_readl(g, timer_time_1_r()); + + if (gpu_timestamp_hi == gpu_timestamp_hi_prev) { + args->gpu_timestamp = + (((u64)gpu_timestamp_hi) << 32) | + gpu_timestamp_lo; + goto clean_up; + } + + /* wrap-around detected, retry */ + gpu_timestamp_hi_prev = gpu_timestamp_hi; + } + + /* too many iterations, bail out */ + gk20a_err(dev_from_gk20a(g), + "Failed to read GPU time. Clock or bus unstable?\n"); + err = -EBUSY; + +clean_up: + gk20a_idle(g->dev); + return err; +} + long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct device *dev = filp->private_data; @@ -859,6 +911,11 @@ long gk20a_ctrl_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg (struct nvgpu_gpu_get_cpu_time_correlation_info_args *)buf); break; + case NVGPU_GPU_IOCTL_GET_GPU_TIME: + err = nvgpu_gpu_get_gpu_time(g, + (struct nvgpu_gpu_get_gpu_time_args *)buf); + break; + default: dev_dbg(dev_from_gk20a(g), "unrecognized gpu ioctl cmd: 0x%x", cmd); err = -ENOTTY; diff --git a/include/uapi/linux/nvgpu.h b/include/uapi/linux/nvgpu.h index d84c5440..cf89b9d8 100644 --- a/include/uapi/linux/nvgpu.h +++ b/include/uapi/linux/nvgpu.h @@ -377,6 +377,14 @@ struct nvgpu_gpu_get_cpu_time_correlation_info_args { __u32 source_id; }; +struct nvgpu_gpu_get_gpu_time_args { + /* raw GPU counter (PTIMER) value */ + __u64 gpu_timestamp; + + /* reserved for future extensions */ + __u64 reserved; +}; + #define NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE \ _IOR(NVGPU_GPU_IOCTL_MAGIC, 1, struct nvgpu_gpu_zcull_get_ctx_size_args) #define NVGPU_GPU_IOCTL_ZCULL_GET_INFO \ @@ -426,8 +434,11 @@ struct nvgpu_gpu_get_cpu_time_correlation_info_args { #define NVGPU_GPU_IOCTL_GET_CPU_TIME_CORRELATION_INFO \ _IOWR(NVGPU_GPU_IOCTL_MAGIC, 24, \ struct nvgpu_gpu_get_cpu_time_correlation_info_args) +#define NVGPU_GPU_IOCTL_GET_GPU_TIME \ + _IOWR(NVGPU_GPU_IOCTL_MAGIC, 25, \ + struct nvgpu_gpu_get_gpu_time_args) #define NVGPU_GPU_IOCTL_LAST \ - _IOC_NR(NVGPU_GPU_IOCTL_GET_CPU_TIME_CORRELATION_INFO) + _IOC_NR(NVGPU_GPU_IOCTL_GET_GPU_TIME) #define NVGPU_GPU_IOCTL_MAX_ARG_SIZE \ sizeof(struct nvgpu_gpu_get_cpu_time_correlation_info_args) -- cgit v1.2.2