aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon.h9
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c105
3 files changed, 45 insertions, 72 deletions
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index 2d7d16e14f9e..ec49dada887d 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -541,9 +541,6 @@ int r600_vb_ib_get(struct radeon_device *rdev)
541void r600_vb_ib_put(struct radeon_device *rdev) 541void r600_vb_ib_put(struct radeon_device *rdev)
542{ 542{
543 radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence); 543 radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
544 mutex_lock(&rdev->ib_pool.mutex);
545 list_add_tail(&rdev->r600_blit.vb_ib->list, &rdev->ib_pool.scheduled_ibs);
546 mutex_unlock(&rdev->ib_pool.mutex);
547 radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); 544 radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
548} 545}
549 546
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 993cdf20d8e6..9f35beed13e8 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -97,6 +97,7 @@ extern int radeon_audio;
97 * symbol; 97 * symbol;
98 */ 98 */
99#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ 99#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
100/* RADEON_IB_POOL_SIZE must be a power of 2 */
100#define RADEON_IB_POOL_SIZE 16 101#define RADEON_IB_POOL_SIZE 16
101#define RADEON_DEBUGFS_MAX_NUM_FILES 32 102#define RADEON_DEBUGFS_MAX_NUM_FILES 32
102#define RADEONFB_CONN_LIMIT 4 103#define RADEONFB_CONN_LIMIT 4
@@ -371,11 +372,12 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev);
371 */ 372 */
372struct radeon_ib { 373struct radeon_ib {
373 struct list_head list; 374 struct list_head list;
374 unsigned long idx; 375 unsigned idx;
375 uint64_t gpu_addr; 376 uint64_t gpu_addr;
376 struct radeon_fence *fence; 377 struct radeon_fence *fence;
377 uint32_t *ptr; 378 uint32_t *ptr;
378 uint32_t length_dw; 379 uint32_t length_dw;
380 bool free;
379}; 381};
380 382
381/* 383/*
@@ -385,11 +387,10 @@ struct radeon_ib {
385struct radeon_ib_pool { 387struct radeon_ib_pool {
386 struct mutex mutex; 388 struct mutex mutex;
387 struct radeon_bo *robj; 389 struct radeon_bo *robj;
388 struct list_head scheduled_ibs;
389 struct list_head bogus_ib; 390 struct list_head bogus_ib;
390 struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; 391 struct radeon_ib ibs[RADEON_IB_POOL_SIZE];
391 bool ready; 392 bool ready;
392 DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE); 393 unsigned head_id;
393}; 394};
394 395
395struct radeon_cp { 396struct radeon_cp {
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index e3bee59ef6c3..38fa14429320 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++) {