drm/radeon/kms: implement timestamp userspace query (v2)
authorMarek Olšák <maraeo@gmail.com>
Thu, 9 Aug 2012 14:34:17 +0000 (16:34 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 13 Aug 2012 14:50:56 +0000 (10:50 -0400)
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>
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
include/drm/radeon_drm.h

index 637280f..d79c639 100644 (file)
@@ -3789,3 +3789,23 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
                WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
        }
 }
+
+/**
+ * r600_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (R6xx-cayman).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index 4b116ae..fd328f4 100644 (file)
 #define RLC_HB_WPTR                                       0x3f1c
 #define RLC_HB_WPTR_LSB_ADDR                              0x3f14
 #define RLC_HB_WPTR_MSB_ADDR                              0x3f18
+#define RLC_GPU_CLOCK_COUNT_LSB                                  0x3f38
+#define RLC_GPU_CLOCK_COUNT_MSB                                  0x3f3c
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                      0x3f40
 #define RLC_MC_CNTL                                       0x3f44
 #define RLC_UCODE_CNTL                                    0x3f48
 #define RLC_UCODE_ADDR                                    0x3f2c
index b237a29..9930419 100644 (file)
@@ -1534,6 +1534,7 @@ struct radeon_device {
        unsigned                debugfs_count;
        /* virtual memory */
        struct radeon_vm_manager        vm_manager;
+       struct mutex                    gpu_clock_mutex;
 };
 
 int radeon_device_init(struct radeon_device *rdev,
index 0d445e7..18c38d1 100644 (file)
@@ -368,6 +368,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        unsigned num_gpu_pages,
                        struct radeon_sa_bo *vb);
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -468,5 +469,6 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id);
 void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
 void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
+uint64_t si_get_gpu_clock(struct radeon_device *rdev);
 
 #endif
index 742af82..d2e2438 100644 (file)
@@ -1009,6 +1009,7 @@ int radeon_device_init(struct radeon_device *rdev,
        atomic_set(&rdev->ih.lock, 0);
        mutex_init(&rdev->gem.mutex);
        mutex_init(&rdev->pm.mutex);
+       mutex_init(&rdev->gpu_clock_mutex);
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
index a7f8ac0..d7269f4 100644 (file)
  *   2.17.0 - add STRMOUT_BASE_UPDATE for r7xx
  *   2.18.0 - r600-eg: allow "invalid" DB formats
  *   2.19.0 - r600-eg: MSAA textures
+ *   2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       19
+#define KMS_DRIVER_MINOR       20
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index 1d73f16..414b4ac 100644 (file)
@@ -29,6 +29,7 @@
 #include "drm_sarea.h"
 #include "radeon.h"
 #include "radeon_drm.h"
+#include "radeon_asic.h"
 
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
@@ -167,17 +168,39 @@ static void radeon_set_filp_rights(struct drm_device *dev,
 int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 {
        struct radeon_device *rdev = dev->dev_private;
-       struct drm_radeon_info *info;
+       struct drm_radeon_info *info = data;
        struct radeon_mode_info *minfo = &rdev->mode_info;
-       uint32_t *value_ptr;
-       uint32_t value;
+       uint32_t value, *value_ptr;
+       uint64_t value64, *value_ptr64;
        struct drm_crtc *crtc;
        int i, found;
 
-       info = data;
+       /* TIMESTAMP is a 64-bit value, needs special handling. */
+       if (info->request == RADEON_INFO_TIMESTAMP) {
+               if (rdev->family >= CHIP_R600) {
+                       value_ptr64 = (uint64_t*)((unsigned long)info->value);
+                       if (rdev->family >= CHIP_TAHITI) {
+                               value64 = si_get_gpu_clock(rdev);
+                       } else {
+                               value64 = r600_get_gpu_clock(rdev);
+                       }
+
+                       if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) {
+                               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
+                               return -EFAULT;
+                       }
+                       return 0;
+               } else {
+                       DRM_DEBUG_KMS("timestamp is r6xx+ only!\n");
+                       return -EINVAL;
+               }
+       }
+
        value_ptr = (uint32_t *)((unsigned long)info->value);
-       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
+       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) {
+               DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
+       }
 
        switch (info->request) {
        case RADEON_INFO_DEVICE_ID:
@@ -337,7 +360,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                return -EINVAL;
        }
        if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
-               DRM_ERROR("copy_to_user\n");
+               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
        }
        return 0;
index c153a7f..0139e22 100644 (file)
@@ -3968,3 +3968,22 @@ void si_fini(struct radeon_device *rdev)
        rdev->bios = NULL;
 }
 
+/**
+ * si_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t si_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index 7869089..ef4815c 100644 (file)
 #define RLC_UCODE_ADDR                                    0xC32C
 #define RLC_UCODE_DATA                                    0xC330
 
+#define RLC_GPU_CLOCK_COUNT_LSB                           0xC338
+#define RLC_GPU_CLOCK_COUNT_MSB                           0xC33C
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC340
 #define RLC_MC_CNTL                                       0xC344
 #define RLC_UCODE_CNTL                                    0xC348
 
index 5805686..dc3a8cd 100644 (file)
@@ -964,6 +964,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_IB_VM_MAX_SIZE     0x0f
 /* max pipes - needed for compute shaders */
 #define RADEON_INFO_MAX_PIPES          0x10
+/* timestamp for GL_ARB_timer_query (OpenGL), returns the current GPU clock */
+#define RADEON_INFO_TIMESTAMP          0x11
 
 struct drm_radeon_info {
        uint32_t                request;