Commit 6759a0a7a0496dbbd4fb062c6a76d61c55d0fbd9

Authored by Marek Olšák
Committed by Alex Deucher
1 parent b51ad12a36

drm/radeon/kms: implement timestamp userspace query (v2)

Returns a snapshot of the GPU clock counter.  Needed
for certain OpenGL extensions.

v2: agd5f
- address Jerome's comments
- add function documentation

Signed-off-by: Marek Olšák <maraeo@gmail.com>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

Showing 10 changed files with 82 additions and 7 deletions Side-by-side Diff

drivers/gpu/drm/radeon/r600.c
... ... @@ -3789,4 +3789,24 @@
3789 3789 WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
3790 3790 }
3791 3791 }
  3792 +
  3793 +/**
  3794 + * r600_get_gpu_clock - return GPU clock counter snapshot
  3795 + *
  3796 + * @rdev: radeon_device pointer
  3797 + *
  3798 + * Fetches a GPU clock counter snapshot (R6xx-cayman).
  3799 + * Returns the 64 bit clock counter snapshot.
  3800 + */
  3801 +uint64_t r600_get_gpu_clock(struct radeon_device *rdev)
  3802 +{
  3803 + uint64_t clock;
  3804 +
  3805 + mutex_lock(&rdev->gpu_clock_mutex);
  3806 + WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
  3807 + clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
  3808 + ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
  3809 + mutex_unlock(&rdev->gpu_clock_mutex);
  3810 + return clock;
  3811 +}
drivers/gpu/drm/radeon/r600d.h
... ... @@ -602,6 +602,9 @@
602 602 #define RLC_HB_WPTR 0x3f1c
603 603 #define RLC_HB_WPTR_LSB_ADDR 0x3f14
604 604 #define RLC_HB_WPTR_MSB_ADDR 0x3f18
  605 +#define RLC_GPU_CLOCK_COUNT_LSB 0x3f38
  606 +#define RLC_GPU_CLOCK_COUNT_MSB 0x3f3c
  607 +#define RLC_CAPTURE_GPU_CLOCK_COUNT 0x3f40
605 608 #define RLC_MC_CNTL 0x3f44
606 609 #define RLC_UCODE_CNTL 0x3f48
607 610 #define RLC_UCODE_ADDR 0x3f2c
drivers/gpu/drm/radeon/radeon.h
... ... @@ -1534,6 +1534,7 @@
1534 1534 unsigned debugfs_count;
1535 1535 /* virtual memory */
1536 1536 struct radeon_vm_manager vm_manager;
  1537 + struct mutex gpu_clock_mutex;
1537 1538 };
1538 1539  
1539 1540 int radeon_device_init(struct radeon_device *rdev,
drivers/gpu/drm/radeon/radeon_asic.h
... ... @@ -368,6 +368,7 @@
368 368 unsigned num_gpu_pages,
369 369 struct radeon_sa_bo *vb);
370 370 int r600_mc_wait_for_idle(struct radeon_device *rdev);
  371 +uint64_t r600_get_gpu_clock(struct radeon_device *rdev);
371 372  
372 373 /*
373 374 * rv770,rv730,rv710,rv740
... ... @@ -468,6 +469,7 @@
468 469 void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
469 470 void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);
470 471 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
  472 +uint64_t si_get_gpu_clock(struct radeon_device *rdev);
471 473  
472 474 #endif
drivers/gpu/drm/radeon/radeon_device.c
... ... @@ -1009,6 +1009,7 @@
1009 1009 atomic_set(&rdev->ih.lock, 0);
1010 1010 mutex_init(&rdev->gem.mutex);
1011 1011 mutex_init(&rdev->pm.mutex);
  1012 + mutex_init(&rdev->gpu_clock_mutex);
1012 1013 init_rwsem(&rdev->pm.mclk_lock);
1013 1014 init_rwsem(&rdev->exclusive_lock);
1014 1015 init_waitqueue_head(&rdev->irq.vblank_queue);
drivers/gpu/drm/radeon/radeon_drv.c
... ... @@ -61,9 +61,10 @@
61 61 * 2.17.0 - add STRMOUT_BASE_UPDATE for r7xx
62 62 * 2.18.0 - r600-eg: allow "invalid" DB formats
63 63 * 2.19.0 - r600-eg: MSAA textures
  64 + * 2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query
64 65 */
65 66 #define KMS_DRIVER_MAJOR 2
66   -#define KMS_DRIVER_MINOR 19
  67 +#define KMS_DRIVER_MINOR 20
67 68 #define KMS_DRIVER_PATCHLEVEL 0
68 69 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
69 70 int radeon_driver_unload_kms(struct drm_device *dev);
drivers/gpu/drm/radeon/radeon_kms.c
... ... @@ -29,6 +29,7 @@
29 29 #include "drm_sarea.h"
30 30 #include "radeon.h"
31 31 #include "radeon_drm.h"
  32 +#include "radeon_asic.h"
32 33  
33 34 #include <linux/vga_switcheroo.h>
34 35 #include <linux/slab.h>
35 36  
36 37  
37 38  
38 39  
... ... @@ -167,17 +168,39 @@
167 168 int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
168 169 {
169 170 struct radeon_device *rdev = dev->dev_private;
170   - struct drm_radeon_info *info;
  171 + struct drm_radeon_info *info = data;
171 172 struct radeon_mode_info *minfo = &rdev->mode_info;
172   - uint32_t *value_ptr;
173   - uint32_t value;
  173 + uint32_t value, *value_ptr;
  174 + uint64_t value64, *value_ptr64;
174 175 struct drm_crtc *crtc;
175 176 int i, found;
176 177  
177   - info = data;
  178 + /* TIMESTAMP is a 64-bit value, needs special handling. */
  179 + if (info->request == RADEON_INFO_TIMESTAMP) {
  180 + if (rdev->family >= CHIP_R600) {
  181 + value_ptr64 = (uint64_t*)((unsigned long)info->value);
  182 + if (rdev->family >= CHIP_TAHITI) {
  183 + value64 = si_get_gpu_clock(rdev);
  184 + } else {
  185 + value64 = r600_get_gpu_clock(rdev);
  186 + }
  187 +
  188 + if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) {
  189 + DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
  190 + return -EFAULT;
  191 + }
  192 + return 0;
  193 + } else {
  194 + DRM_DEBUG_KMS("timestamp is r6xx+ only!\n");
  195 + return -EINVAL;
  196 + }
  197 + }
  198 +
178 199 value_ptr = (uint32_t *)((unsigned long)info->value);
179   - if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
  200 + if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) {
  201 + DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
180 202 return -EFAULT;
  203 + }
181 204  
182 205 switch (info->request) {
183 206 case RADEON_INFO_DEVICE_ID:
... ... @@ -337,7 +360,7 @@
337 360 return -EINVAL;
338 361 }
339 362 if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
340   - DRM_ERROR("copy_to_user\n");
  363 + DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
341 364 return -EFAULT;
342 365 }
343 366 return 0;
drivers/gpu/drm/radeon/si.c
... ... @@ -3967,4 +3967,24 @@
3967 3967 kfree(rdev->bios);
3968 3968 rdev->bios = NULL;
3969 3969 }
  3970 +
  3971 +/**
  3972 + * si_get_gpu_clock - return GPU clock counter snapshot
  3973 + *
  3974 + * @rdev: radeon_device pointer
  3975 + *
  3976 + * Fetches a GPU clock counter snapshot (SI).
  3977 + * Returns the 64 bit clock counter snapshot.
  3978 + */
  3979 +uint64_t si_get_gpu_clock(struct radeon_device *rdev)
  3980 +{
  3981 + uint64_t clock;
  3982 +
  3983 + mutex_lock(&rdev->gpu_clock_mutex);
  3984 + WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
  3985 + clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
  3986 + ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
  3987 + mutex_unlock(&rdev->gpu_clock_mutex);
  3988 + return clock;
  3989 +}
drivers/gpu/drm/radeon/sid.h
... ... @@ -698,6 +698,9 @@
698 698 #define RLC_UCODE_ADDR 0xC32C
699 699 #define RLC_UCODE_DATA 0xC330
700 700  
  701 +#define RLC_GPU_CLOCK_COUNT_LSB 0xC338
  702 +#define RLC_GPU_CLOCK_COUNT_MSB 0xC33C
  703 +#define RLC_CAPTURE_GPU_CLOCK_COUNT 0xC340
701 704 #define RLC_MC_CNTL 0xC344
702 705 #define RLC_UCODE_CNTL 0xC348
703 706  
include/drm/radeon_drm.h
... ... @@ -964,6 +964,8 @@
964 964 #define RADEON_INFO_IB_VM_MAX_SIZE 0x0f
965 965 /* max pipes - needed for compute shaders */
966 966 #define RADEON_INFO_MAX_PIPES 0x10
  967 +/* timestamp for GL_ARB_timer_query (OpenGL), returns the current GPU clock */
  968 +#define RADEON_INFO_TIMESTAMP 0x11
967 969  
968 970 struct drm_radeon_info {
969 971 uint32_t request;