aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_ring.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2010-02-15 15:36:13 -0500
committerDave Airlie <airlied@redhat.com>2010-02-15 16:59:23 -0500
commite821767bebdae6a46f6d897a4385f6218bee7f27 (patch)
tree0a97f6a74f946c12d4821d9d82c8255e951d026f /drivers/gpu/drm/radeon/radeon_ring.c
parent2e98f10a7a87ebae4dcc3949028a32008b46ceef (diff)
drm/radeon/kms: fix indirect buffer management V2
There is 3 different distinct states for an indirect buffer (IB) : 1- free with no fence 2- free with a fence 3- non free (fence doesn't matter) Previous code mixed case 2 & 3 in a single one leading to possible catastrophique failure. This patch rework the handling and properly separate each case. So when you get ib we set the ib as non free and fence status doesn't matter. Fence become active (ie has a meaning for the ib code) once the ib is scheduled or free. This patch also get rid of the alloc bitmap as it was overkill, we know go through IB pool list like in a ring buffer as the oldest IB is the first one the will be free. Fix : https://bugs.freedesktop.org/show_bug.cgi?id=26438 and likely other bugs. V2 remove the scheduled list, it's useless now, fix free ib scanning Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_ring.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c105
1 files changed, 40 insertions, 65 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index e3bee59ef6c..38fa1442932 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -71,68 +71,55 @@ int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib)
71{ 71{
72 struct radeon_fence *fence; 72 struct radeon_fence *fence;
73 struct radeon_ib *nib; 73 struct radeon_ib *nib;
74 unsigned long i; 74 int r = 0, i, c;
75 int r = 0;
76 75
77 *ib = NULL; 76 *ib = NULL;
78 r = radeon_fence_create(rdev, &fence); 77 r = radeon_fence_create(rdev, &fence);
79 if (r) { 78 if (r) {
80 DRM_ERROR("failed to create fence for new IB\n"); 79 dev_err(rdev->dev, "failed to create fence for new IB\n");
81 return r; 80 return r;
82 } 81 }
83 mutex_lock(&rdev->ib_pool.mutex); 82 mutex_lock(&rdev->ib_pool.mutex);
84 i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); 83 for (i = rdev->ib_pool.head_id, c = 0, nib = NULL; c < RADEON_IB_POOL_SIZE; c++, i++) {
85 if (i < RADEON_IB_POOL_SIZE) { 84 i &= (RADEON_IB_POOL_SIZE - 1);
86 set_bit(i, rdev->ib_pool.alloc_bm); 85 if (rdev->ib_pool.ibs[i].free) {
87 rdev->ib_pool.ibs[i].length_dw = 0; 86 nib = &rdev->ib_pool.ibs[i];
88 *ib = &rdev->ib_pool.ibs[i]; 87 break;
89 mutex_unlock(&rdev->ib_pool.mutex); 88 }
90 goto out;
91 } 89 }
92 if (list_empty(&rdev->ib_pool.scheduled_ibs)) { 90 if (nib == NULL) {
93 /* we go do nothings here */ 91 /* This should never happen, it means we allocated all
92 * IB and haven't scheduled one yet, return EBUSY to
93 * userspace hoping that on ioctl recall we get better
94 * luck
95 */
96 dev_err(rdev->dev, "no free indirect buffer !\n");
94 mutex_unlock(&rdev->ib_pool.mutex); 97 mutex_unlock(&rdev->ib_pool.mutex);
95 DRM_ERROR("all IB allocated none scheduled.\n"); 98 radeon_fence_unref(&fence);
96 r = -EINVAL; 99 return -EBUSY;
97 goto out;
98 } 100 }
99 /* get the first ib on the scheduled list */ 101 rdev->ib_pool.head_id = (nib->idx + 1) & (RADEON_IB_POOL_SIZE - 1);
100 nib = list_entry(rdev->ib_pool.scheduled_ibs.next, 102 nib->free = false;
101 struct radeon_ib, list); 103 if (nib->fence) {
102 if (nib->fence == NULL) {
103 /* we go do nothings here */
104 mutex_unlock(&rdev->ib_pool.mutex); 104 mutex_unlock(&rdev->ib_pool.mutex);
105 DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx); 105 r = radeon_fence_wait(nib->fence, false);
106 r = -EINVAL; 106 if (r) {
107 goto out; 107 dev_err(rdev->dev, "error waiting fence of IB(%u:0x%016lX:%u)\n",
108 } 108 nib->idx, (unsigned long)nib->gpu_addr, nib->length_dw);
109 mutex_unlock(&rdev->ib_pool.mutex); 109 mutex_lock(&rdev->ib_pool.mutex);
110 110 nib->free = true;
111 r = radeon_fence_wait(nib->fence, false); 111 mutex_unlock(&rdev->ib_pool.mutex);
112 if (r) { 112 radeon_fence_unref(&fence);
113 DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx, 113 return r;
114 (unsigned long)nib->gpu_addr, nib->length_dw); 114 }
115 DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n"); 115 mutex_lock(&rdev->ib_pool.mutex);
116 goto out;
117 } 116 }
118 radeon_fence_unref(&nib->fence); 117 radeon_fence_unref(&nib->fence);
119 118 nib->fence = fence;
120 nib->length_dw = 0; 119 nib->length_dw = 0;
121
122 /* scheduled list is accessed here */
123 mutex_lock(&rdev->ib_pool.mutex);
124 list_del(&nib->list);
125 INIT_LIST_HEAD(&nib->list);
126 mutex_unlock(&rdev->ib_pool.mutex); 120 mutex_unlock(&rdev->ib_pool.mutex);
127
128 *ib = nib; 121 *ib = nib;
129out: 122 return 0;
130 if (r) {
131 radeon_fence_unref(&fence);
132 } else {
133 (*ib)->fence = fence;
134 }
135 return r;
136} 123}
137 124
138void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib) 125void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
@@ -144,18 +131,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
144 return; 131 return;
145 } 132 }
146 mutex_lock(&rdev->ib_pool.mutex); 133 mutex_lock(&rdev->ib_pool.mutex);
147 if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) { 134 tmp->free = true;
148 /* IB is scheduled & not signaled don't do anythings */
149 mutex_unlock(&rdev->ib_pool.mutex);
150 return;
151 }
152 list_del(&tmp->list);
153 INIT_LIST_HEAD(&tmp->list);
154 if (tmp->fence)
155 radeon_fence_unref(&tmp->fence);
156
157 tmp->length_dw = 0;
158 clear_bit(tmp->idx, rdev->ib_pool.alloc_bm);
159 mutex_unlock(&rdev->ib_pool.mutex); 135 mutex_unlock(&rdev->ib_pool.mutex);
160} 136}
161 137
@@ -165,7 +141,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
165 141
166 if (!ib->length_dw || !rdev->cp.ready) { 142 if (!ib->length_dw || !rdev->cp.ready) {
167 /* TODO: Nothings in the ib we should report. */ 143 /* TODO: Nothings in the ib we should report. */
168 DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx); 144 DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx);
169 return -EINVAL; 145 return -EINVAL;
170 } 146 }
171 147
@@ -178,7 +154,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
178 radeon_ring_ib_execute(rdev, ib); 154 radeon_ring_ib_execute(rdev, ib);
179 radeon_fence_emit(rdev, ib->fence); 155 radeon_fence_emit(rdev, ib->fence);
180 mutex_lock(&rdev->ib_pool.mutex); 156 mutex_lock(&rdev->ib_pool.mutex);
181 list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs); 157 /* once scheduled IB is considered free and protected by the fence */
158 ib->free = true;
182 mutex_unlock(&rdev->ib_pool.mutex); 159 mutex_unlock(&rdev->ib_pool.mutex);
183 radeon_ring_unlock_commit(rdev); 160 radeon_ring_unlock_commit(rdev);
184 return 0; 161 return 0;
@@ -195,7 +172,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
195 return 0; 172 return 0;
196 INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib); 173 INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
197 /* Allocate 1M object buffer */ 174 /* Allocate 1M object buffer */
198 INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs);
199 r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024, 175 r = radeon_bo_create(rdev, NULL, RADEON_IB_POOL_SIZE*64*1024,
200 true, RADEON_GEM_DOMAIN_GTT, 176 true, RADEON_GEM_DOMAIN_GTT,
201 &rdev->ib_pool.robj); 177 &rdev->ib_pool.robj);
@@ -226,9 +202,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
226 rdev->ib_pool.ibs[i].ptr = ptr + offset; 202 rdev->ib_pool.ibs[i].ptr = ptr + offset;
227 rdev->ib_pool.ibs[i].idx = i; 203 rdev->ib_pool.ibs[i].idx = i;
228 rdev->ib_pool.ibs[i].length_dw = 0; 204 rdev->ib_pool.ibs[i].length_dw = 0;
229 INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list); 205 rdev->ib_pool.ibs[i].free = true;
230 } 206 }
231 bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE); 207 rdev->ib_pool.head_id = 0;
232 rdev->ib_pool.ready = true; 208 rdev->ib_pool.ready = true;
233 DRM_INFO("radeon: ib pool ready.\n"); 209 DRM_INFO("radeon: ib pool ready.\n");
234 if (radeon_debugfs_ib_init(rdev)) { 210 if (radeon_debugfs_ib_init(rdev)) {
@@ -246,7 +222,6 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
246 } 222 }
247 mutex_lock(&rdev->ib_pool.mutex); 223 mutex_lock(&rdev->ib_pool.mutex);
248 radeon_ib_bogus_cleanup(rdev); 224 radeon_ib_bogus_cleanup(rdev);
249 bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
250 if (rdev->ib_pool.robj) { 225 if (rdev->ib_pool.robj) {
251 r = radeon_bo_reserve(rdev->ib_pool.robj, false); 226 r = radeon_bo_reserve(rdev->ib_pool.robj, false);
252 if (likely(r == 0)) { 227 if (likely(r == 0)) {
@@ -395,7 +370,7 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
395 if (ib == NULL) { 370 if (ib == NULL) {
396 return 0; 371 return 0;
397 } 372 }
398 seq_printf(m, "IB %04lu\n", ib->idx); 373 seq_printf(m, "IB %04u\n", ib->idx);
399 seq_printf(m, "IB fence %p\n", ib->fence); 374 seq_printf(m, "IB fence %p\n", ib->fence);
400 seq_printf(m, "IB size %05u dwords\n", ib->length_dw); 375 seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
401 for (i = 0; i < ib->length_dw; i++) { 376 for (i = 0; i < ib->length_dw; i++) {