drm/radeon: use inline functions to calc sa_bo addr
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / radeon / radeon_ring.c
index cc33b3d7c33b8f4bfa293cd3ce973fdc8b92aff6..116be5e83141bb627f7fe887891e5074d834ef64 100644 (file)
@@ -34,7 +34,7 @@
 #include "atom.h"
 
 int radeon_debugfs_ib_init(struct radeon_device *rdev);
-int radeon_debugfs_ring_init(struct radeon_device *rdev);
+int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
 
 u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)
 {
@@ -82,7 +82,7 @@ bool radeon_ib_try_free(struct radeon_device *rdev, struct radeon_ib *ib)
        bool done = false;
 
        /* only free ib which have been emited */
-       if (ib->fence && ib->fence->emitted) {
+       if (ib->fence && ib->fence->seq < RADEON_FENCE_NOTEMITED_SEQ) {
                if (radeon_fence_signaled(ib->fence)) {
                        radeon_fence_unref(&ib->fence);
                        radeon_sa_bo_free(rdev, &ib->sa_bo);
@@ -127,10 +127,8 @@ retry:
                                             size, 256);
                        if (!r) {
                                *ib = &rdev->ib_pool.ibs[idx];
-                               (*ib)->ptr = rdev->ib_pool.sa_manager.cpu_ptr;
-                               (*ib)->ptr += ((*ib)->sa_bo.offset >> 2);
-                               (*ib)->gpu_addr = rdev->ib_pool.sa_manager.gpu_addr;
-                               (*ib)->gpu_addr += (*ib)->sa_bo.offset;
+                               (*ib)->ptr = radeon_sa_bo_cpu_addr(&(*ib)->sa_bo);
+                               (*ib)->gpu_addr = radeon_sa_bo_gpu_addr(&(*ib)->sa_bo);
                                (*ib)->fence = fence;
                                (*ib)->vm_id = 0;
                                (*ib)->is_const_ib = false;
@@ -149,8 +147,9 @@ retry:
        /* this should be rare event, ie all ib scheduled none signaled yet.
         */
        for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
-               if (rdev->ib_pool.ibs[idx].fence && rdev->ib_pool.ibs[idx].fence->emitted) {
-                       r = radeon_fence_wait(rdev->ib_pool.ibs[idx].fence, false);
+               struct radeon_fence *fence = rdev->ib_pool.ibs[idx].fence;
+               if (fence && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) {
+                       r = radeon_fence_wait(fence, false);
                        if (!r) {
                                goto retry;
                        }
@@ -173,7 +172,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
                return;
        }
        radeon_mutex_lock(&rdev->ib_pool.mutex);
-       if (tmp->fence && !tmp->fence->emitted) {
+       if (tmp->fence && tmp->fence->seq == RADEON_FENCE_NOTEMITED_SEQ) {
                radeon_sa_bo_free(rdev, &tmp->sa_bo);
                radeon_fence_unref(&tmp->fence);
        }
@@ -237,9 +236,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
        if (radeon_debugfs_ib_init(rdev)) {
                DRM_ERROR("Failed to register debugfs file for IB !\n");
        }
-       if (radeon_debugfs_ring_init(rdev)) {
-               DRM_ERROR("Failed to register debugfs file for rings !\n");
-       }
        radeon_mutex_unlock(&rdev->ib_pool.mutex);
        return 0;
 }
@@ -270,6 +266,36 @@ int radeon_ib_pool_suspend(struct radeon_device *rdev)
        return radeon_sa_bo_manager_suspend(rdev, &rdev->ib_pool.sa_manager);
 }
 
+int radeon_ib_ring_tests(struct radeon_device *rdev)
+{
+       unsigned i;
+       int r;
+
+       for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+               struct radeon_ring *ring = &rdev->ring[i];
+
+               if (!ring->ready)
+                       continue;
+
+               r = radeon_ib_test(rdev, i, ring);
+               if (r) {
+                       ring->ready = false;
+
+                       if (i == RADEON_RING_TYPE_GFX_INDEX) {
+                               /* oh, oh, that's really bad */
+                               DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r);
+                               rdev->accel_working = false;
+                               return r;
+
+                       } else {
+                               /* still not good, but we can live with it */
+                               DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r);
+                       }
+               }
+       }
+       return 0;
+}
+
 /*
  * Ring.
  */
@@ -319,7 +345,7 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi
                if (ndw < ring->ring_free_dw) {
                        break;
                }
-               r = radeon_fence_wait_next(rdev, radeon_ring_index(rdev, ring));
+               r = radeon_fence_wait_next_locked(rdev, radeon_ring_index(rdev, ring));
                if (r)
                        return r;
        }
@@ -332,10 +358,10 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig
 {
        int r;
 
-       mutex_lock(&ring->mutex);
+       mutex_lock(&rdev->ring_lock);
        r = radeon_ring_alloc(rdev, ring, ndw);
        if (r) {
-               mutex_unlock(&ring->mutex);
+               mutex_unlock(&rdev->ring_lock);
                return r;
        }
        return 0;
@@ -360,13 +386,85 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
 void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring)
 {
        radeon_ring_commit(rdev, ring);
-       mutex_unlock(&ring->mutex);
+       mutex_unlock(&rdev->ring_lock);
 }
 
-void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring)
+void radeon_ring_undo(struct radeon_ring *ring)
 {
        ring->wptr = ring->wptr_old;
-       mutex_unlock(&ring->mutex);
+}
+
+void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       radeon_ring_undo(ring);
+       mutex_unlock(&rdev->ring_lock);
+}
+
+void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       int r;
+
+       radeon_ring_free_size(rdev, ring);
+       if (ring->rptr == ring->wptr) {
+               r = radeon_ring_alloc(rdev, ring, 1);
+               if (!r) {
+                       radeon_ring_write(ring, ring->nop);
+                       radeon_ring_commit(rdev, ring);
+               }
+       }
+}
+
+void radeon_ring_lockup_update(struct radeon_ring *ring)
+{
+       ring->last_rptr = ring->rptr;
+       ring->last_activity = jiffies;
+}
+
+/**
+ * radeon_ring_test_lockup() - check if ring is lockedup by recording information
+ * @rdev:       radeon device structure
+ * @ring:       radeon_ring structure holding ring information
+ *
+ * We don't need to initialize the lockup tracking information as we will either
+ * have CP rptr to a different value of jiffies wrap around which will force
+ * initialization of the lockup tracking informations.
+ *
+ * A possible false positivie is if we get call after while and last_cp_rptr ==
+ * the current CP rptr, even if it's unlikely it might happen. To avoid this
+ * if the elapsed time since last call is bigger than 2 second than we return
+ * false and update the tracking information. Due to this the caller must call
+ * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported
+ * the fencing code should be cautious about that.
+ *
+ * Caller should write to the ring to force CP to do something so we don't get
+ * false positive when CP is just gived nothing to do.
+ *
+ **/
+bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       unsigned long cjiffies, elapsed;
+       uint32_t rptr;
+
+       cjiffies = jiffies;
+       if (!time_after(cjiffies, ring->last_activity)) {
+               /* likely a wrap around */
+               radeon_ring_lockup_update(ring);
+               return false;
+       }
+       rptr = RREG32(ring->rptr_reg);
+       ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+       if (ring->rptr != ring->last_rptr) {
+               /* CP is still working no lockup */
+               radeon_ring_lockup_update(ring);
+               return false;
+       }
+       elapsed = jiffies_to_msecs(cjiffies - ring->last_activity);
+       if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) {
+               dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
+               return true;
+       }
+       /* give a chance to the GPU ... */
+       return false;
 }
 
 int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size,
@@ -411,6 +509,9 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
        }
        ring->ptr_mask = (ring->ring_size / 4) - 1;
        ring->ring_free_dw = ring->ring_size / 4;
+       if (radeon_debugfs_ring_init(rdev, ring)) {
+               DRM_ERROR("Failed to register debugfs file for rings !\n");
+       }
        return 0;
 }
 
@@ -419,11 +520,12 @@ void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *ring)
        int r;
        struct radeon_bo *ring_obj;
 
-       mutex_lock(&ring->mutex);
+       mutex_lock(&rdev->ring_lock);
        ring_obj = ring->ring_obj;
+       ring->ready = false;
        ring->ring = NULL;
        ring->ring_obj = NULL;
-       mutex_unlock(&ring->mutex);
+       mutex_unlock(&rdev->ring_lock);
 
        if (ring_obj) {
                r = radeon_bo_reserve(ring_obj, false);
@@ -501,17 +603,24 @@ static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
 static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE];
 #endif
 
-int radeon_debugfs_ring_init(struct radeon_device *rdev)
+int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring)
 {
 #if defined(CONFIG_DEBUG_FS)
-       if (rdev->family >= CHIP_CAYMAN)
-               return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list,
-                                               ARRAY_SIZE(radeon_debugfs_ring_info_list));
-       else
-               return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, 1);
-#else
-       return 0;
+       unsigned i;
+       for (i = 0; i < ARRAY_SIZE(radeon_debugfs_ring_info_list); ++i) {
+               struct drm_info_list *info = &radeon_debugfs_ring_info_list[i];
+               int ridx = *(int*)radeon_debugfs_ring_info_list[i].data;
+               unsigned r;
+
+               if (&rdev->ring[ridx] != ring)
+                       continue;
+
+               r = radeon_debugfs_add_files(rdev, info, 1);
+               if (r)
+                       return r;
+       }
 #endif
+       return 0;
 }
 
 int radeon_debugfs_ib_init(struct radeon_device *rdev)