diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-08-20 05:40:46 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-08-21 08:34:11 -0400 |
commit | 6c085a728cf000ac1865d66f8c9b52935558b328 (patch) | |
tree | 416d56b284e9aba4da4aee1d6c6a8f5fa16a934e /drivers/gpu/drm/i915/i915_gem.c | |
parent | 225067eedf1f4d4065940232c9069fcb255206ee (diff) |
drm/i915: Track unbound pages
When dealing with a working set larger than the GATT, or even the
mappable aperture when touching through the GTT, we end up with evicting
objects only to rebind them at a new offset again later. Moving an
object into and out of the GTT requires clflushing the pages, thus
causing a double-clflush penalty for rebinding.
To avoid having to clflush on rebinding, we can track the pages as they
are evicted from the GTT and only relinquish those pages on memory
pressure.
As usual, if it were not for the handling of out-of-memory condition and
having to manually shrink our own bo caches, it would be a net reduction
of code. Alas.
Note: The patch also contains a few changes to the last-hope
evict_everything logic in i916_gem_execbuffer.c - we no longer try to
only evict the purgeable stuff in a first try (since that's superflous
and only helps in OOM corner-cases, not fragmented-gtt trashing
situations).
Also, the extraction of the get_pages retry loop from bind_to_gtt (and
other callsites) to get_pages should imo have been a separate patch.
v2: Ditch the newly added put_pages (for unbound objects only) in
i915_gem_reset. A quick irc discussion hasn't revealed any important
reason for this, so if we need this, I'd like to have a git blame'able
explanation for it.
v3: Undo the s/drm_malloc_ab/kmalloc/ in get_pages that Chris noticed.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: Split out code movements and rant a bit in the commit message
with a few Notes. Done v2]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 288 |
1 files changed, 143 insertions, 145 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0f70c2acfefa..462a8f2ad3a2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -55,6 +55,8 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, | |||
55 | 55 | ||
56 | static int i915_gem_inactive_shrink(struct shrinker *shrinker, | 56 | static int i915_gem_inactive_shrink(struct shrinker *shrinker, |
57 | struct shrink_control *sc); | 57 | struct shrink_control *sc); |
58 | static long i915_gem_purge(struct drm_i915_private *dev_priv, long target); | ||
59 | static void i915_gem_shrink_all(struct drm_i915_private *dev_priv); | ||
58 | static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); | 60 | static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); |
59 | 61 | ||
60 | static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) | 62 | static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) |
@@ -140,7 +142,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) | |||
140 | static inline bool | 142 | static inline bool |
141 | i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) | 143 | i915_gem_object_is_inactive(struct drm_i915_gem_object *obj) |
142 | { | 144 | { |
143 | return !obj->active; | 145 | return obj->gtt_space && !obj->active; |
144 | } | 146 | } |
145 | 147 | ||
146 | int | 148 | int |
@@ -179,7 +181,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, | |||
179 | 181 | ||
180 | pinned = 0; | 182 | pinned = 0; |
181 | mutex_lock(&dev->struct_mutex); | 183 | mutex_lock(&dev->struct_mutex); |
182 | list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) | 184 | list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) |
183 | if (obj->pin_count) | 185 | if (obj->pin_count) |
184 | pinned += obj->gtt_space->size; | 186 | pinned += obj->gtt_space->size; |
185 | mutex_unlock(&dev->struct_mutex); | 187 | mutex_unlock(&dev->struct_mutex); |
@@ -423,9 +425,11 @@ i915_gem_shmem_pread(struct drm_device *dev, | |||
423 | * anyway again before the next pread happens. */ | 425 | * anyway again before the next pread happens. */ |
424 | if (obj->cache_level == I915_CACHE_NONE) | 426 | if (obj->cache_level == I915_CACHE_NONE) |
425 | needs_clflush = 1; | 427 | needs_clflush = 1; |
426 | ret = i915_gem_object_set_to_gtt_domain(obj, false); | 428 | if (obj->gtt_space) { |
427 | if (ret) | 429 | ret = i915_gem_object_set_to_gtt_domain(obj, false); |
428 | return ret; | 430 | if (ret) |
431 | return ret; | ||
432 | } | ||
429 | } | 433 | } |
430 | 434 | ||
431 | offset = args->offset; | 435 | offset = args->offset; |
@@ -751,9 +755,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev, | |||
751 | * right away and we therefore have to clflush anyway. */ | 755 | * right away and we therefore have to clflush anyway. */ |
752 | if (obj->cache_level == I915_CACHE_NONE) | 756 | if (obj->cache_level == I915_CACHE_NONE) |
753 | needs_clflush_after = 1; | 757 | needs_clflush_after = 1; |
754 | ret = i915_gem_object_set_to_gtt_domain(obj, true); | 758 | if (obj->gtt_space) { |
755 | if (ret) | 759 | ret = i915_gem_object_set_to_gtt_domain(obj, true); |
756 | return ret; | 760 | if (ret) |
761 | return ret; | ||
762 | } | ||
757 | } | 763 | } |
758 | /* Same trick applies for invalidate partially written cachelines before | 764 | /* Same trick applies for invalidate partially written cachelines before |
759 | * writing. */ | 765 | * writing. */ |
@@ -1366,17 +1372,28 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) | |||
1366 | return obj->madv == I915_MADV_DONTNEED; | 1372 | return obj->madv == I915_MADV_DONTNEED; |
1367 | } | 1373 | } |
1368 | 1374 | ||
1369 | static void | 1375 | static int |
1370 | i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) | 1376 | i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) |
1371 | { | 1377 | { |
1372 | int page_count = obj->base.size / PAGE_SIZE; | 1378 | int page_count = obj->base.size / PAGE_SIZE; |
1373 | int i; | 1379 | int ret, i; |
1374 | 1380 | ||
1375 | if (!obj->pages) | 1381 | if (obj->pages == NULL) |
1376 | return; | 1382 | return 0; |
1377 | 1383 | ||
1384 | BUG_ON(obj->gtt_space); | ||
1378 | BUG_ON(obj->madv == __I915_MADV_PURGED); | 1385 | BUG_ON(obj->madv == __I915_MADV_PURGED); |
1379 | 1386 | ||
1387 | ret = i915_gem_object_set_to_cpu_domain(obj, true); | ||
1388 | if (ret) { | ||
1389 | /* In the event of a disaster, abandon all caches and | ||
1390 | * hope for the best. | ||
1391 | */ | ||
1392 | WARN_ON(ret != -EIO); | ||
1393 | i915_gem_clflush_object(obj); | ||
1394 | obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; | ||
1395 | } | ||
1396 | |||
1380 | if (i915_gem_object_needs_bit17_swizzle(obj)) | 1397 | if (i915_gem_object_needs_bit17_swizzle(obj)) |
1381 | i915_gem_object_save_bit_17_swizzle(obj); | 1398 | i915_gem_object_save_bit_17_swizzle(obj); |
1382 | 1399 | ||
@@ -1396,37 +1413,112 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) | |||
1396 | 1413 | ||
1397 | drm_free_large(obj->pages); | 1414 | drm_free_large(obj->pages); |
1398 | obj->pages = NULL; | 1415 | obj->pages = NULL; |
1416 | |||
1417 | list_del(&obj->gtt_list); | ||
1418 | |||
1419 | if (i915_gem_object_is_purgeable(obj)) | ||
1420 | i915_gem_object_truncate(obj); | ||
1421 | |||
1422 | return 0; | ||
1423 | } | ||
1424 | |||
1425 | static long | ||
1426 | i915_gem_purge(struct drm_i915_private *dev_priv, long target) | ||
1427 | { | ||
1428 | struct drm_i915_gem_object *obj, *next; | ||
1429 | long count = 0; | ||
1430 | |||
1431 | list_for_each_entry_safe(obj, next, | ||
1432 | &dev_priv->mm.unbound_list, | ||
1433 | gtt_list) { | ||
1434 | if (i915_gem_object_is_purgeable(obj) && | ||
1435 | i915_gem_object_put_pages_gtt(obj) == 0) { | ||
1436 | count += obj->base.size >> PAGE_SHIFT; | ||
1437 | if (count >= target) | ||
1438 | return count; | ||
1439 | } | ||
1440 | } | ||
1441 | |||
1442 | list_for_each_entry_safe(obj, next, | ||
1443 | &dev_priv->mm.inactive_list, | ||
1444 | mm_list) { | ||
1445 | if (i915_gem_object_is_purgeable(obj) && | ||
1446 | i915_gem_object_unbind(obj) == 0 && | ||
1447 | i915_gem_object_put_pages_gtt(obj) == 0) { | ||
1448 | count += obj->base.size >> PAGE_SHIFT; | ||
1449 | if (count >= target) | ||
1450 | return count; | ||
1451 | } | ||
1452 | } | ||
1453 | |||
1454 | return count; | ||
1455 | } | ||
1456 | |||
1457 | static void | ||
1458 | i915_gem_shrink_all(struct drm_i915_private *dev_priv) | ||
1459 | { | ||
1460 | struct drm_i915_gem_object *obj, *next; | ||
1461 | |||
1462 | i915_gem_evict_everything(dev_priv->dev); | ||
1463 | |||
1464 | list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list) | ||
1465 | i915_gem_object_put_pages_gtt(obj); | ||
1399 | } | 1466 | } |
1400 | 1467 | ||
1401 | int | 1468 | int |
1402 | i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, | 1469 | i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) |
1403 | gfp_t gfpmask) | ||
1404 | { | 1470 | { |
1471 | struct drm_i915_private *dev_priv = obj->base.dev->dev_private; | ||
1405 | int page_count, i; | 1472 | int page_count, i; |
1406 | struct address_space *mapping; | 1473 | struct address_space *mapping; |
1407 | struct inode *inode; | ||
1408 | struct page *page; | 1474 | struct page *page; |
1475 | gfp_t gfp; | ||
1409 | 1476 | ||
1410 | if (obj->pages || obj->sg_table) | 1477 | if (obj->pages || obj->sg_table) |
1411 | return 0; | 1478 | return 0; |
1412 | 1479 | ||
1480 | /* Assert that the object is not currently in any GPU domain. As it | ||
1481 | * wasn't in the GTT, there shouldn't be any way it could have been in | ||
1482 | * a GPU cache | ||
1483 | */ | ||
1484 | BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); | ||
1485 | BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); | ||
1486 | |||
1413 | /* Get the list of pages out of our struct file. They'll be pinned | 1487 | /* Get the list of pages out of our struct file. They'll be pinned |
1414 | * at this point until we release them. | 1488 | * at this point until we release them. |
1415 | */ | 1489 | */ |
1416 | page_count = obj->base.size / PAGE_SIZE; | 1490 | page_count = obj->base.size / PAGE_SIZE; |
1417 | BUG_ON(obj->pages != NULL); | ||
1418 | obj->pages = drm_malloc_ab(page_count, sizeof(struct page *)); | 1491 | obj->pages = drm_malloc_ab(page_count, sizeof(struct page *)); |
1419 | if (obj->pages == NULL) | 1492 | if (obj->pages == NULL) |
1420 | return -ENOMEM; | 1493 | return -ENOMEM; |
1421 | 1494 | ||
1422 | inode = obj->base.filp->f_path.dentry->d_inode; | 1495 | /* Fail silently without starting the shrinker */ |
1423 | mapping = inode->i_mapping; | 1496 | mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; |
1424 | gfpmask |= mapping_gfp_mask(mapping); | 1497 | gfp = mapping_gfp_mask(mapping); |
1425 | 1498 | gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; | |
1499 | gfp &= ~(__GFP_IO | __GFP_WAIT); | ||
1426 | for (i = 0; i < page_count; i++) { | 1500 | for (i = 0; i < page_count; i++) { |
1427 | page = shmem_read_mapping_page_gfp(mapping, i, gfpmask); | 1501 | page = shmem_read_mapping_page_gfp(mapping, i, gfp); |
1428 | if (IS_ERR(page)) | 1502 | if (IS_ERR(page)) { |
1429 | goto err_pages; | 1503 | i915_gem_purge(dev_priv, page_count); |
1504 | page = shmem_read_mapping_page_gfp(mapping, i, gfp); | ||
1505 | } | ||
1506 | if (IS_ERR(page)) { | ||
1507 | /* We've tried hard to allocate the memory by reaping | ||
1508 | * our own buffer, now let the real VM do its job and | ||
1509 | * go down in flames if truly OOM. | ||
1510 | */ | ||
1511 | gfp &= ~(__GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD); | ||
1512 | gfp |= __GFP_IO | __GFP_WAIT; | ||
1513 | |||
1514 | i915_gem_shrink_all(dev_priv); | ||
1515 | page = shmem_read_mapping_page_gfp(mapping, i, gfp); | ||
1516 | if (IS_ERR(page)) | ||
1517 | goto err_pages; | ||
1518 | |||
1519 | gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; | ||
1520 | gfp &= ~(__GFP_IO | __GFP_WAIT); | ||
1521 | } | ||
1430 | 1522 | ||
1431 | obj->pages[i] = page; | 1523 | obj->pages[i] = page; |
1432 | } | 1524 | } |
@@ -1434,6 +1526,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, | |||
1434 | if (i915_gem_object_needs_bit17_swizzle(obj)) | 1526 | if (i915_gem_object_needs_bit17_swizzle(obj)) |
1435 | i915_gem_object_do_bit_17_swizzle(obj); | 1527 | i915_gem_object_do_bit_17_swizzle(obj); |
1436 | 1528 | ||
1529 | list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); | ||
1437 | return 0; | 1530 | return 0; |
1438 | 1531 | ||
1439 | err_pages: | 1532 | err_pages: |
@@ -1698,6 +1791,7 @@ void i915_gem_reset(struct drm_device *dev) | |||
1698 | obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; | 1791 | obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; |
1699 | } | 1792 | } |
1700 | 1793 | ||
1794 | |||
1701 | /* The fence registers are invalidated so clear them out */ | 1795 | /* The fence registers are invalidated so clear them out */ |
1702 | i915_gem_reset_fences(dev); | 1796 | i915_gem_reset_fences(dev); |
1703 | } | 1797 | } |
@@ -2209,22 +2303,6 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) | |||
2209 | 2303 | ||
2210 | i915_gem_object_finish_gtt(obj); | 2304 | i915_gem_object_finish_gtt(obj); |
2211 | 2305 | ||
2212 | /* Move the object to the CPU domain to ensure that | ||
2213 | * any possible CPU writes while it's not in the GTT | ||
2214 | * are flushed when we go to remap it. | ||
2215 | */ | ||
2216 | if (ret == 0) | ||
2217 | ret = i915_gem_object_set_to_cpu_domain(obj, 1); | ||
2218 | if (ret == -ERESTARTSYS) | ||
2219 | return ret; | ||
2220 | if (ret) { | ||
2221 | /* In the event of a disaster, abandon all caches and | ||
2222 | * hope for the best. | ||
2223 | */ | ||
2224 | i915_gem_clflush_object(obj); | ||
2225 | obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; | ||
2226 | } | ||
2227 | |||
2228 | /* release the fence reg _after_ flushing */ | 2306 | /* release the fence reg _after_ flushing */ |
2229 | ret = i915_gem_object_put_fence(obj); | 2307 | ret = i915_gem_object_put_fence(obj); |
2230 | if (ret) | 2308 | if (ret) |
@@ -2240,10 +2318,8 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) | |||
2240 | } | 2318 | } |
2241 | i915_gem_gtt_finish_object(obj); | 2319 | i915_gem_gtt_finish_object(obj); |
2242 | 2320 | ||
2243 | i915_gem_object_put_pages_gtt(obj); | 2321 | list_del(&obj->mm_list); |
2244 | 2322 | list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); | |
2245 | list_del_init(&obj->gtt_list); | ||
2246 | list_del_init(&obj->mm_list); | ||
2247 | /* Avoid an unnecessary call to unbind on rebind. */ | 2323 | /* Avoid an unnecessary call to unbind on rebind. */ |
2248 | obj->map_and_fenceable = true; | 2324 | obj->map_and_fenceable = true; |
2249 | 2325 | ||
@@ -2251,10 +2327,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) | |||
2251 | obj->gtt_space = NULL; | 2327 | obj->gtt_space = NULL; |
2252 | obj->gtt_offset = 0; | 2328 | obj->gtt_offset = 0; |
2253 | 2329 | ||
2254 | if (i915_gem_object_is_purgeable(obj)) | 2330 | return 0; |
2255 | i915_gem_object_truncate(obj); | ||
2256 | |||
2257 | return ret; | ||
2258 | } | 2331 | } |
2259 | 2332 | ||
2260 | static int i915_ring_idle(struct intel_ring_buffer *ring) | 2333 | static int i915_ring_idle(struct intel_ring_buffer *ring) |
@@ -2667,7 +2740,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, | |||
2667 | struct drm_device *dev = obj->base.dev; | 2740 | struct drm_device *dev = obj->base.dev; |
2668 | drm_i915_private_t *dev_priv = dev->dev_private; | 2741 | drm_i915_private_t *dev_priv = dev->dev_private; |
2669 | struct drm_mm_node *free_space; | 2742 | struct drm_mm_node *free_space; |
2670 | gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN; | ||
2671 | u32 size, fence_size, fence_alignment, unfenced_alignment; | 2743 | u32 size, fence_size, fence_alignment, unfenced_alignment; |
2672 | bool mappable, fenceable; | 2744 | bool mappable, fenceable; |
2673 | int ret; | 2745 | int ret; |
@@ -2707,6 +2779,10 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, | |||
2707 | return -E2BIG; | 2779 | return -E2BIG; |
2708 | } | 2780 | } |
2709 | 2781 | ||
2782 | ret = i915_gem_object_get_pages_gtt(obj); | ||
2783 | if (ret) | ||
2784 | return ret; | ||
2785 | |||
2710 | search_free: | 2786 | search_free: |
2711 | if (map_and_fenceable) | 2787 | if (map_and_fenceable) |
2712 | free_space = | 2788 | free_space = |
@@ -2733,9 +2809,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, | |||
2733 | false); | 2809 | false); |
2734 | } | 2810 | } |
2735 | if (obj->gtt_space == NULL) { | 2811 | if (obj->gtt_space == NULL) { |
2736 | /* If the gtt is empty and we're still having trouble | ||
2737 | * fitting our object in, we're out of memory. | ||
2738 | */ | ||
2739 | ret = i915_gem_evict_something(dev, size, alignment, | 2812 | ret = i915_gem_evict_something(dev, size, alignment, |
2740 | obj->cache_level, | 2813 | obj->cache_level, |
2741 | map_and_fenceable); | 2814 | map_and_fenceable); |
@@ -2752,55 +2825,20 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, | |||
2752 | return -EINVAL; | 2825 | return -EINVAL; |
2753 | } | 2826 | } |
2754 | 2827 | ||
2755 | ret = i915_gem_object_get_pages_gtt(obj, gfpmask); | ||
2756 | if (ret) { | ||
2757 | drm_mm_put_block(obj->gtt_space); | ||
2758 | obj->gtt_space = NULL; | ||
2759 | |||
2760 | if (ret == -ENOMEM) { | ||
2761 | /* first try to reclaim some memory by clearing the GTT */ | ||
2762 | ret = i915_gem_evict_everything(dev, false); | ||
2763 | if (ret) { | ||
2764 | /* now try to shrink everyone else */ | ||
2765 | if (gfpmask) { | ||
2766 | gfpmask = 0; | ||
2767 | goto search_free; | ||
2768 | } | ||
2769 | |||
2770 | return -ENOMEM; | ||
2771 | } | ||
2772 | |||
2773 | goto search_free; | ||
2774 | } | ||
2775 | |||
2776 | return ret; | ||
2777 | } | ||
2778 | 2828 | ||
2779 | ret = i915_gem_gtt_prepare_object(obj); | 2829 | ret = i915_gem_gtt_prepare_object(obj); |
2780 | if (ret) { | 2830 | if (ret) { |
2781 | i915_gem_object_put_pages_gtt(obj); | ||
2782 | drm_mm_put_block(obj->gtt_space); | 2831 | drm_mm_put_block(obj->gtt_space); |
2783 | obj->gtt_space = NULL; | 2832 | obj->gtt_space = NULL; |
2784 | 2833 | return ret; | |
2785 | if (i915_gem_evict_everything(dev, false)) | ||
2786 | return ret; | ||
2787 | |||
2788 | goto search_free; | ||
2789 | } | 2834 | } |
2790 | 2835 | ||
2791 | if (!dev_priv->mm.aliasing_ppgtt) | 2836 | if (!dev_priv->mm.aliasing_ppgtt) |
2792 | i915_gem_gtt_bind_object(obj, obj->cache_level); | 2837 | i915_gem_gtt_bind_object(obj, obj->cache_level); |
2793 | 2838 | ||
2794 | list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list); | 2839 | list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list); |
2795 | list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); | 2840 | list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); |
2796 | 2841 | ||
2797 | /* Assert that the object is not currently in any GPU domain. As it | ||
2798 | * wasn't in the GTT, there shouldn't be any way it could have been in | ||
2799 | * a GPU cache | ||
2800 | */ | ||
2801 | BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); | ||
2802 | BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); | ||
2803 | |||
2804 | obj->gtt_offset = obj->gtt_space->start; | 2842 | obj->gtt_offset = obj->gtt_space->start; |
2805 | 2843 | ||
2806 | fenceable = | 2844 | fenceable = |
@@ -3464,9 +3502,8 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, | |||
3464 | if (obj->madv != __I915_MADV_PURGED) | 3502 | if (obj->madv != __I915_MADV_PURGED) |
3465 | obj->madv = args->madv; | 3503 | obj->madv = args->madv; |
3466 | 3504 | ||
3467 | /* if the object is no longer bound, discard its backing storage */ | 3505 | /* if the object is no longer attached, discard its backing storage */ |
3468 | if (i915_gem_object_is_purgeable(obj) && | 3506 | if (i915_gem_object_is_purgeable(obj) && obj->pages == NULL) |
3469 | obj->gtt_space == NULL) | ||
3470 | i915_gem_object_truncate(obj); | 3507 | i915_gem_object_truncate(obj); |
3471 | 3508 | ||
3472 | args->retained = obj->madv != __I915_MADV_PURGED; | 3509 | args->retained = obj->madv != __I915_MADV_PURGED; |
@@ -3573,6 +3610,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) | |||
3573 | dev_priv->mm.interruptible = was_interruptible; | 3610 | dev_priv->mm.interruptible = was_interruptible; |
3574 | } | 3611 | } |
3575 | 3612 | ||
3613 | i915_gem_object_put_pages_gtt(obj); | ||
3576 | if (obj->base.map_list.map) | 3614 | if (obj->base.map_list.map) |
3577 | drm_gem_free_mmap_offset(&obj->base); | 3615 | drm_gem_free_mmap_offset(&obj->base); |
3578 | 3616 | ||
@@ -3605,7 +3643,7 @@ i915_gem_idle(struct drm_device *dev) | |||
3605 | 3643 | ||
3606 | /* Under UMS, be paranoid and evict. */ | 3644 | /* Under UMS, be paranoid and evict. */ |
3607 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 3645 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3608 | i915_gem_evict_everything(dev, false); | 3646 | i915_gem_evict_everything(dev); |
3609 | 3647 | ||
3610 | i915_gem_reset_fences(dev); | 3648 | i915_gem_reset_fences(dev); |
3611 | 3649 | ||
@@ -3963,8 +4001,9 @@ i915_gem_load(struct drm_device *dev) | |||
3963 | 4001 | ||
3964 | INIT_LIST_HEAD(&dev_priv->mm.active_list); | 4002 | INIT_LIST_HEAD(&dev_priv->mm.active_list); |
3965 | INIT_LIST_HEAD(&dev_priv->mm.inactive_list); | 4003 | INIT_LIST_HEAD(&dev_priv->mm.inactive_list); |
4004 | INIT_LIST_HEAD(&dev_priv->mm.unbound_list); | ||
4005 | INIT_LIST_HEAD(&dev_priv->mm.bound_list); | ||
3966 | INIT_LIST_HEAD(&dev_priv->mm.fence_list); | 4006 | INIT_LIST_HEAD(&dev_priv->mm.fence_list); |
3967 | INIT_LIST_HEAD(&dev_priv->mm.gtt_list); | ||
3968 | for (i = 0; i < I915_NUM_RINGS; i++) | 4007 | for (i = 0; i < I915_NUM_RINGS; i++) |
3969 | init_ring_lists(&dev_priv->ring[i]); | 4008 | init_ring_lists(&dev_priv->ring[i]); |
3970 | for (i = 0; i < I915_MAX_NUM_FENCES; i++) | 4009 | for (i = 0; i < I915_MAX_NUM_FENCES; i++) |
@@ -4209,13 +4248,6 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file) | |||
4209 | } | 4248 | } |
4210 | 4249 | ||
4211 | static int | 4250 | static int |
4212 | i915_gpu_is_active(struct drm_device *dev) | ||
4213 | { | ||
4214 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
4215 | return !list_empty(&dev_priv->mm.active_list); | ||
4216 | } | ||
4217 | |||
4218 | static int | ||
4219 | i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | 4251 | i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) |
4220 | { | 4252 | { |
4221 | struct drm_i915_private *dev_priv = | 4253 | struct drm_i915_private *dev_priv = |
@@ -4223,60 +4255,26 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) | |||
4223 | struct drm_i915_private, | 4255 | struct drm_i915_private, |
4224 | mm.inactive_shrinker); | 4256 | mm.inactive_shrinker); |
4225 | struct drm_device *dev = dev_priv->dev; | 4257 | struct drm_device *dev = dev_priv->dev; |
4226 | struct drm_i915_gem_object *obj, *next; | 4258 | struct drm_i915_gem_object *obj; |
4227 | int nr_to_scan = sc->nr_to_scan; | 4259 | int nr_to_scan = sc->nr_to_scan; |
4228 | int cnt; | 4260 | int cnt; |
4229 | 4261 | ||
4230 | if (!mutex_trylock(&dev->struct_mutex)) | 4262 | if (!mutex_trylock(&dev->struct_mutex)) |
4231 | return 0; | 4263 | return 0; |
4232 | 4264 | ||
4233 | /* "fast-path" to count number of available objects */ | 4265 | if (nr_to_scan) { |
4234 | if (nr_to_scan == 0) { | 4266 | nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan); |
4235 | cnt = 0; | 4267 | if (nr_to_scan > 0) |
4236 | list_for_each_entry(obj, | 4268 | i915_gem_shrink_all(dev_priv); |
4237 | &dev_priv->mm.inactive_list, | ||
4238 | mm_list) | ||
4239 | cnt++; | ||
4240 | mutex_unlock(&dev->struct_mutex); | ||
4241 | return cnt / 100 * sysctl_vfs_cache_pressure; | ||
4242 | } | 4269 | } |
4243 | 4270 | ||
4244 | rescan: | ||
4245 | /* first scan for clean buffers */ | ||
4246 | i915_gem_retire_requests(dev); | ||
4247 | |||
4248 | list_for_each_entry_safe(obj, next, | ||
4249 | &dev_priv->mm.inactive_list, | ||
4250 | mm_list) { | ||
4251 | if (i915_gem_object_is_purgeable(obj)) { | ||
4252 | if (i915_gem_object_unbind(obj) == 0 && | ||
4253 | --nr_to_scan == 0) | ||
4254 | break; | ||
4255 | } | ||
4256 | } | ||
4257 | |||
4258 | /* second pass, evict/count anything still on the inactive list */ | ||
4259 | cnt = 0; | 4271 | cnt = 0; |
4260 | list_for_each_entry_safe(obj, next, | 4272 | list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) |
4261 | &dev_priv->mm.inactive_list, | 4273 | cnt += obj->base.size >> PAGE_SHIFT; |
4262 | mm_list) { | 4274 | list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) |
4263 | if (nr_to_scan && | 4275 | if (obj->pin_count == 0) |
4264 | i915_gem_object_unbind(obj) == 0) | 4276 | cnt += obj->base.size >> PAGE_SHIFT; |
4265 | nr_to_scan--; | ||
4266 | else | ||
4267 | cnt++; | ||
4268 | } | ||
4269 | 4277 | ||
4270 | if (nr_to_scan && i915_gpu_is_active(dev)) { | ||
4271 | /* | ||
4272 | * We are desperate for pages, so as a last resort, wait | ||
4273 | * for the GPU to finish and discard whatever we can. | ||
4274 | * This has a dramatic impact to reduce the number of | ||
4275 | * OOM-killer events whilst running the GPU aggressively. | ||
4276 | */ | ||
4277 | if (i915_gpu_idle(dev) == 0) | ||
4278 | goto rescan; | ||
4279 | } | ||
4280 | mutex_unlock(&dev->struct_mutex); | 4278 | mutex_unlock(&dev->struct_mutex); |
4281 | return cnt / 100 * sysctl_vfs_cache_pressure; | 4279 | return cnt; |
4282 | } | 4280 | } |