diff options
author | Christian König <deathsimple@vodafone.de> | 2012-07-11 15:07:57 -0400 |
---|---|---|
committer | Christian König <deathsimple@vodafone.de> | 2012-07-18 07:17:44 -0400 |
commit | bfb38d35c1cacb182d8bbda23379397bffeafc8c (patch) | |
tree | 7eebc054ee7eb1bcb68becc64eaa309f0f69b50b /drivers/gpu/drm/radeon/radeon_sa.c | |
parent | 246fa345a1b72fddb9b2b81f32abd615a5d1c0af (diff) |
drm/radeon: let sa manager block for fences to wait for v2
Otherwise we can encounter out of memory situations under extreme load.
v2: add documentation for the new function
Signed-off-by: Christian König <deathsimple@vodafone.de>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_sa.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_sa.c | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index 81dbb5b946ef..4e771240fdd0 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c | |||
@@ -54,7 +54,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev, | |||
54 | { | 54 | { |
55 | int i, r; | 55 | int i, r; |
56 | 56 | ||
57 | spin_lock_init(&sa_manager->lock); | 57 | init_waitqueue_head(&sa_manager->wq); |
58 | sa_manager->bo = NULL; | 58 | sa_manager->bo = NULL; |
59 | sa_manager->size = size; | 59 | sa_manager->size = size; |
60 | sa_manager->domain = domain; | 60 | sa_manager->domain = domain; |
@@ -211,6 +211,39 @@ static bool radeon_sa_bo_try_alloc(struct radeon_sa_manager *sa_manager, | |||
211 | return false; | 211 | return false; |
212 | } | 212 | } |
213 | 213 | ||
214 | /** | ||
215 | * radeon_sa_event - Check if we can stop waiting | ||
216 | * | ||
217 | * @sa_manager: pointer to the sa_manager | ||
218 | * @size: number of bytes we want to allocate | ||
219 | * @align: alignment we need to match | ||
220 | * | ||
221 | * Check if either there is a fence we can wait for or | ||
222 | * enough free memory to satisfy the allocation directly | ||
223 | */ | ||
224 | static bool radeon_sa_event(struct radeon_sa_manager *sa_manager, | ||
225 | unsigned size, unsigned align) | ||
226 | { | ||
227 | unsigned soffset, eoffset, wasted; | ||
228 | int i; | ||
229 | |||
230 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { | ||
231 | if (!list_empty(&sa_manager->flist[i])) { | ||
232 | return true; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | soffset = radeon_sa_bo_hole_soffset(sa_manager); | ||
237 | eoffset = radeon_sa_bo_hole_eoffset(sa_manager); | ||
238 | wasted = (align - (soffset % align)) % align; | ||
239 | |||
240 | if ((eoffset - soffset) >= (size + wasted)) { | ||
241 | return true; | ||
242 | } | ||
243 | |||
244 | return false; | ||
245 | } | ||
246 | |||
214 | static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, | 247 | static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager, |
215 | struct radeon_fence **fences, | 248 | struct radeon_fence **fences, |
216 | unsigned *tries) | 249 | unsigned *tries) |
@@ -297,8 +330,8 @@ int radeon_sa_bo_new(struct radeon_device *rdev, | |||
297 | INIT_LIST_HEAD(&(*sa_bo)->olist); | 330 | INIT_LIST_HEAD(&(*sa_bo)->olist); |
298 | INIT_LIST_HEAD(&(*sa_bo)->flist); | 331 | INIT_LIST_HEAD(&(*sa_bo)->flist); |
299 | 332 | ||
300 | spin_lock(&sa_manager->lock); | 333 | spin_lock(&sa_manager->wq.lock); |
301 | do { | 334 | while(1) { |
302 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { | 335 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
303 | fences[i] = NULL; | 336 | fences[i] = NULL; |
304 | tries[i] = 0; | 337 | tries[i] = 0; |
@@ -309,30 +342,34 @@ int radeon_sa_bo_new(struct radeon_device *rdev, | |||
309 | 342 | ||
310 | if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo, | 343 | if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo, |
311 | size, align)) { | 344 | size, align)) { |
312 | spin_unlock(&sa_manager->lock); | 345 | spin_unlock(&sa_manager->wq.lock); |
313 | return 0; | 346 | return 0; |
314 | } | 347 | } |
315 | 348 | ||
316 | /* see if we can skip over some allocations */ | 349 | /* see if we can skip over some allocations */ |
317 | } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); | 350 | } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); |
318 | 351 | ||
319 | if (block) { | 352 | if (!block) { |
320 | spin_unlock(&sa_manager->lock); | 353 | break; |
321 | r = radeon_fence_wait_any(rdev, fences, false); | 354 | } |
322 | spin_lock(&sa_manager->lock); | 355 | |
323 | if (r) { | 356 | spin_unlock(&sa_manager->wq.lock); |
324 | /* if we have nothing to wait for we | 357 | r = radeon_fence_wait_any(rdev, fences, false); |
325 | are practically out of memory */ | 358 | spin_lock(&sa_manager->wq.lock); |
326 | if (r == -ENOENT) { | 359 | /* if we have nothing to wait for block */ |
327 | r = -ENOMEM; | 360 | if (r == -ENOENT) { |
328 | } | 361 | r = wait_event_interruptible_locked( |
329 | goto out_err; | 362 | sa_manager->wq, |
330 | } | 363 | radeon_sa_event(sa_manager, size, align) |
364 | ); | ||
365 | } | ||
366 | if (r) { | ||
367 | goto out_err; | ||
331 | } | 368 | } |
332 | } while (block); | 369 | }; |
333 | 370 | ||
334 | out_err: | 371 | out_err: |
335 | spin_unlock(&sa_manager->lock); | 372 | spin_unlock(&sa_manager->wq.lock); |
336 | kfree(*sa_bo); | 373 | kfree(*sa_bo); |
337 | *sa_bo = NULL; | 374 | *sa_bo = NULL; |
338 | return r; | 375 | return r; |
@@ -348,7 +385,7 @@ void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **sa_bo, | |||
348 | } | 385 | } |
349 | 386 | ||
350 | sa_manager = (*sa_bo)->manager; | 387 | sa_manager = (*sa_bo)->manager; |
351 | spin_lock(&sa_manager->lock); | 388 | spin_lock(&sa_manager->wq.lock); |
352 | if (fence && !radeon_fence_signaled(fence)) { | 389 | if (fence && !radeon_fence_signaled(fence)) { |
353 | (*sa_bo)->fence = radeon_fence_ref(fence); | 390 | (*sa_bo)->fence = radeon_fence_ref(fence); |
354 | list_add_tail(&(*sa_bo)->flist, | 391 | list_add_tail(&(*sa_bo)->flist, |
@@ -356,7 +393,8 @@ void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **sa_bo, | |||
356 | } else { | 393 | } else { |
357 | radeon_sa_bo_remove_locked(*sa_bo); | 394 | radeon_sa_bo_remove_locked(*sa_bo); |
358 | } | 395 | } |
359 | spin_unlock(&sa_manager->lock); | 396 | wake_up_all_locked(&sa_manager->wq); |
397 | spin_unlock(&sa_manager->wq.lock); | ||
360 | *sa_bo = NULL; | 398 | *sa_bo = NULL; |
361 | } | 399 | } |
362 | 400 | ||
@@ -366,7 +404,7 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, | |||
366 | { | 404 | { |
367 | struct radeon_sa_bo *i; | 405 | struct radeon_sa_bo *i; |
368 | 406 | ||
369 | spin_lock(&sa_manager->lock); | 407 | spin_lock(&sa_manager->wq.lock); |
370 | list_for_each_entry(i, &sa_manager->olist, olist) { | 408 | list_for_each_entry(i, &sa_manager->olist, olist) { |
371 | if (&i->olist == sa_manager->hole) { | 409 | if (&i->olist == sa_manager->hole) { |
372 | seq_printf(m, ">"); | 410 | seq_printf(m, ">"); |
@@ -381,6 +419,6 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, | |||
381 | } | 419 | } |
382 | seq_printf(m, "\n"); | 420 | seq_printf(m, "\n"); |
383 | } | 421 | } |
384 | spin_unlock(&sa_manager->lock); | 422 | spin_unlock(&sa_manager->wq.lock); |
385 | } | 423 | } |
386 | #endif | 424 | #endif |