diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 8930d66f2204..8339f7a47cb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | |||
@@ -920,17 +920,175 @@ static const struct drm_info_list amdgpu_debugfs_list[] = { | |||
920 | {"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt}, | 920 | {"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt}, |
921 | }; | 921 | }; |
922 | 922 | ||
923 | static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring, | ||
924 | struct dma_fence **fences) | ||
925 | { | ||
926 | struct amdgpu_fence_driver *drv = &ring->fence_drv; | ||
927 | uint32_t sync_seq, last_seq; | ||
928 | |||
929 | last_seq = atomic_read(&ring->fence_drv.last_seq); | ||
930 | sync_seq = ring->fence_drv.sync_seq; | ||
931 | |||
932 | last_seq &= drv->num_fences_mask; | ||
933 | sync_seq &= drv->num_fences_mask; | ||
934 | |||
935 | do { | ||
936 | struct dma_fence *fence, **ptr; | ||
937 | |||
938 | ++last_seq; | ||
939 | last_seq &= drv->num_fences_mask; | ||
940 | ptr = &drv->fences[last_seq]; | ||
941 | |||
942 | fence = rcu_dereference_protected(*ptr, 1); | ||
943 | RCU_INIT_POINTER(*ptr, NULL); | ||
944 | |||
945 | if (!fence) | ||
946 | continue; | ||
947 | |||
948 | fences[last_seq] = fence; | ||
949 | |||
950 | } while (last_seq != sync_seq); | ||
951 | } | ||
952 | |||
953 | static void amdgpu_ib_preempt_signal_fences(struct dma_fence **fences, | ||
954 | int length) | ||
955 | { | ||
956 | int i; | ||
957 | struct dma_fence *fence; | ||
958 | |||
959 | for (i = 0; i < length; i++) { | ||
960 | fence = fences[i]; | ||
961 | if (!fence) | ||
962 | continue; | ||
963 | dma_fence_signal(fence); | ||
964 | dma_fence_put(fence); | ||
965 | } | ||
966 | } | ||
967 | |||
968 | static void amdgpu_ib_preempt_job_recovery(struct drm_gpu_scheduler *sched) | ||
969 | { | ||
970 | struct drm_sched_job *s_job; | ||
971 | struct dma_fence *fence; | ||
972 | |||
973 | spin_lock(&sched->job_list_lock); | ||
974 | list_for_each_entry(s_job, &sched->ring_mirror_list, node) { | ||
975 | fence = sched->ops->run_job(s_job); | ||
976 | dma_fence_put(fence); | ||
977 | } | ||
978 | spin_unlock(&sched->job_list_lock); | ||
979 | } | ||
980 | |||
981 | static int amdgpu_debugfs_ib_preempt(void *data, u64 val) | ||
982 | { | ||
983 | int r, resched, length; | ||
984 | struct amdgpu_ring *ring; | ||
985 | struct drm_sched_job *s_job; | ||
986 | struct amdgpu_job *job; | ||
987 | struct dma_fence **fences = NULL; | ||
988 | struct amdgpu_device *adev = (struct amdgpu_device *)data; | ||
989 | |||
990 | if (val >= AMDGPU_MAX_RINGS) | ||
991 | return -EINVAL; | ||
992 | |||
993 | ring = adev->rings[val]; | ||
994 | |||
995 | if (!ring || !ring->funcs->preempt_ib || !ring->sched.thread) | ||
996 | return -EINVAL; | ||
997 | |||
998 | /* the last preemption failed */ | ||
999 | if (ring->trail_seq != le32_to_cpu(*ring->trail_fence_cpu_addr)) | ||
1000 | return -EBUSY; | ||
1001 | |||
1002 | length = ring->fence_drv.num_fences_mask + 1; | ||
1003 | fences = kcalloc(length, sizeof(void *), GFP_KERNEL); | ||
1004 | if (!fences) | ||
1005 | return -ENOMEM; | ||
1006 | |||
1007 | /* stop the scheduler */ | ||
1008 | kthread_park(ring->sched.thread); | ||
1009 | |||
1010 | resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); | ||
1011 | |||
1012 | /* preempt the IB */ | ||
1013 | r = amdgpu_ring_preempt_ib(ring); | ||
1014 | if (r) { | ||
1015 | DRM_WARN("failed to preempt ring %d\n", ring->idx); | ||
1016 | goto failure; | ||
1017 | } | ||
1018 | |||
1019 | amdgpu_fence_process(ring); | ||
1020 | |||
1021 | if (atomic_read(&ring->fence_drv.last_seq) != | ||
1022 | ring->fence_drv.sync_seq) { | ||
1023 | DRM_INFO("ring %d was preempted\n", ring->idx); | ||
1024 | |||
1025 | /* swap out the old fences */ | ||
1026 | amdgpu_ib_preempt_fences_swap(ring, fences); | ||
1027 | |||
1028 | amdgpu_fence_driver_force_completion(ring); | ||
1029 | |||
1030 | s_job = list_first_entry_or_null( | ||
1031 | &ring->sched.ring_mirror_list, | ||
1032 | struct drm_sched_job, node); | ||
1033 | if (s_job) { | ||
1034 | job = to_amdgpu_job(s_job); | ||
1035 | /* mark the job as preempted */ | ||
1036 | /* job->preemption_status |= | ||
1037 | AMDGPU_IB_PREEMPTED; */ | ||
1038 | } | ||
1039 | |||
1040 | /* resubmit unfinished jobs */ | ||
1041 | amdgpu_ib_preempt_job_recovery(&ring->sched); | ||
1042 | |||
1043 | /* wait for jobs finished */ | ||
1044 | amdgpu_fence_wait_empty(ring); | ||
1045 | |||
1046 | /* signal the old fences */ | ||
1047 | amdgpu_ib_preempt_signal_fences(fences, length); | ||
1048 | } | ||
1049 | |||
1050 | failure: | ||
1051 | /* restart the scheduler */ | ||
1052 | kthread_unpark(ring->sched.thread); | ||
1053 | |||
1054 | ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched); | ||
1055 | |||
1056 | if (fences) | ||
1057 | kfree(fences); | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | DEFINE_SIMPLE_ATTRIBUTE(fops_ib_preempt, NULL, | ||
1063 | amdgpu_debugfs_ib_preempt, "%llu\n"); | ||
1064 | |||
923 | int amdgpu_debugfs_init(struct amdgpu_device *adev) | 1065 | int amdgpu_debugfs_init(struct amdgpu_device *adev) |
924 | { | 1066 | { |
1067 | adev->debugfs_preempt = | ||
1068 | debugfs_create_file("amdgpu_preempt_ib", 0600, | ||
1069 | adev->ddev->primary->debugfs_root, | ||
1070 | (void *)adev, &fops_ib_preempt); | ||
1071 | if (!(adev->debugfs_preempt)) { | ||
1072 | DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n"); | ||
1073 | return -EIO; | ||
1074 | } | ||
1075 | |||
925 | return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, | 1076 | return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, |
926 | ARRAY_SIZE(amdgpu_debugfs_list)); | 1077 | ARRAY_SIZE(amdgpu_debugfs_list)); |
927 | } | 1078 | } |
928 | 1079 | ||
1080 | void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev) | ||
1081 | { | ||
1082 | if (adev->debugfs_preempt) | ||
1083 | debugfs_remove(adev->debugfs_preempt); | ||
1084 | } | ||
1085 | |||
929 | #else | 1086 | #else |
930 | int amdgpu_debugfs_init(struct amdgpu_device *adev) | 1087 | int amdgpu_debugfs_init(struct amdgpu_device *adev) |
931 | { | 1088 | { |
932 | return 0; | 1089 | return 0; |
933 | } | 1090 | } |
1091 | void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev) { } | ||
934 | int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) | 1092 | int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) |
935 | { | 1093 | { |
936 | return 0; | 1094 | return 0; |