Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: add mcbp unit test in debugfs (v3)

The MCBP unit test is used to test the functionality of MCBP.
It emualtes to send preemption request and resubmit the unfinished
jobs.

v2: squash in fixes (Alex)
v3: squash in memory leak fix (Jack)

Acked-by: Hawking Zhang <Hawking.Zhang@amd.com>
Signed-off-by: Jack Xiao <Jack.Xiao@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Jack Xiao and committed by
Alex Deucher
6698a3d0 43974dac

+161
+1
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 762 762 struct amdgpu_debugfs debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS]; 763 763 unsigned debugfs_count; 764 764 #if defined(CONFIG_DEBUG_FS) 765 + struct dentry *debugfs_preempt; 765 766 struct dentry *debugfs_regs[AMDGPU_DEBUGFS_MAX_COMPONENTS]; 766 767 #endif 767 768 struct amdgpu_atif *atif;
+158
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
··· 920 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 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 1076 return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, 926 1077 ARRAY_SIZE(amdgpu_debugfs_list)); 1078 + } 1079 + 1080 + void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev) 1081 + { 1082 + if (adev->debugfs_preempt) 1083 + debugfs_remove(adev->debugfs_preempt); 927 1084 } 928 1085 929 1086 #else ··· 1088 931 { 1089 932 return 0; 1090 933 } 934 + void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev) { } 1091 935 int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) 1092 936 { 1093 937 return 0;
+1
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h
··· 34 34 int amdgpu_debugfs_regs_init(struct amdgpu_device *adev); 35 35 void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev); 36 36 int amdgpu_debugfs_init(struct amdgpu_device *adev); 37 + void amdgpu_debugfs_preempt_cleanup(struct amdgpu_device *adev); 37 38 int amdgpu_debugfs_add_files(struct amdgpu_device *adev, 38 39 const struct drm_info_list *files, 39 40 unsigned nfiles);
+1
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
··· 2837 2837 device_remove_file(adev->dev, &dev_attr_pcie_replay_count); 2838 2838 amdgpu_ucode_sysfs_fini(adev); 2839 2839 amdgpu_pmu_fini(adev); 2840 + amdgpu_debugfs_preempt_cleanup(adev); 2840 2841 } 2841 2842 2842 2843