aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-06-01 10:20:22 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-20 08:22:57 -0400
commit9da3da660d8c19a54f6e93361d147509be3fff84 (patch)
tree3479ef13a733975a02dd679e3fc9ae0872e3be25 /drivers/gpu/drm/i915/i915_gem.c
parentf60d7f0c1d55a935475ab394955cafddefaa6533 (diff)
drm/i915: Replace the array of pages with a scatterlist
Rather than have multiple data structures for describing our page layout in conjunction with the array of pages, we can migrate all users over to a scatterlist. One major advantage, other than unifying the page tracking structures, this offers is that we replace the vmalloc'ed array (which can be up to a megabyte in size) with a chain of individual pages which helps reduce memory pressure. The disadvantage is that we then do not have a simple array to iterate, or to access randomly. The common case for this is in the relocation processing, which will typically fit within a single scatterlist page and so be almost the same cost as the simple array. For iterating over the array, the extra function call could be optimised away, but in reality is an insignificant cost of either binding the pages, or performing the pwrite/pread. v2: Fix drm_clflush_sg() to not invoke wbinvd as well! And fix the trivial compile error from rebasing. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> 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.c79
1 files changed, 55 insertions, 24 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 26c8bf9c5fa6..8f001fa155a1 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -411,6 +411,8 @@ i915_gem_shmem_pread(struct drm_device *dev,
411 int hit_slowpath = 0; 411 int hit_slowpath = 0;
412 int prefaulted = 0; 412 int prefaulted = 0;
413 int needs_clflush = 0; 413 int needs_clflush = 0;
414 struct scatterlist *sg;
415 int i;
414 416
415 user_data = (char __user *) (uintptr_t) args->data_ptr; 417 user_data = (char __user *) (uintptr_t) args->data_ptr;
416 remain = args->size; 418 remain = args->size;
@@ -439,9 +441,15 @@ i915_gem_shmem_pread(struct drm_device *dev,
439 441
440 offset = args->offset; 442 offset = args->offset;
441 443
442 while (remain > 0) { 444 for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
443 struct page *page; 445 struct page *page;
444 446
447 if (i < offset >> PAGE_SHIFT)
448 continue;
449
450 if (remain <= 0)
451 break;
452
445 /* Operation in this page 453 /* Operation in this page
446 * 454 *
447 * shmem_page_offset = offset within page in shmem file 455 * shmem_page_offset = offset within page in shmem file
@@ -452,7 +460,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
452 if ((shmem_page_offset + page_length) > PAGE_SIZE) 460 if ((shmem_page_offset + page_length) > PAGE_SIZE)
453 page_length = PAGE_SIZE - shmem_page_offset; 461 page_length = PAGE_SIZE - shmem_page_offset;
454 462
455 page = obj->pages[offset >> PAGE_SHIFT]; 463 page = sg_page(sg);
456 page_do_bit17_swizzling = obj_do_bit17_swizzling && 464 page_do_bit17_swizzling = obj_do_bit17_swizzling &&
457 (page_to_phys(page) & (1 << 17)) != 0; 465 (page_to_phys(page) & (1 << 17)) != 0;
458 466
@@ -731,6 +739,8 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
731 int hit_slowpath = 0; 739 int hit_slowpath = 0;
732 int needs_clflush_after = 0; 740 int needs_clflush_after = 0;
733 int needs_clflush_before = 0; 741 int needs_clflush_before = 0;
742 int i;
743 struct scatterlist *sg;
734 744
735 user_data = (char __user *) (uintptr_t) args->data_ptr; 745 user_data = (char __user *) (uintptr_t) args->data_ptr;
736 remain = args->size; 746 remain = args->size;
@@ -765,10 +775,16 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
765 offset = args->offset; 775 offset = args->offset;
766 obj->dirty = 1; 776 obj->dirty = 1;
767 777
768 while (remain > 0) { 778 for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
769 struct page *page; 779 struct page *page;
770 int partial_cacheline_write; 780 int partial_cacheline_write;
771 781
782 if (i < offset >> PAGE_SHIFT)
783 continue;
784
785 if (remain <= 0)
786 break;
787
772 /* Operation in this page 788 /* Operation in this page
773 * 789 *
774 * shmem_page_offset = offset within page in shmem file 790 * shmem_page_offset = offset within page in shmem file
@@ -787,7 +803,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
787 ((shmem_page_offset | page_length) 803 ((shmem_page_offset | page_length)
788 & (boot_cpu_data.x86_clflush_size - 1)); 804 & (boot_cpu_data.x86_clflush_size - 1));
789 805
790 page = obj->pages[offset >> PAGE_SHIFT]; 806 page = sg_page(sg);
791 page_do_bit17_swizzling = obj_do_bit17_swizzling && 807 page_do_bit17_swizzling = obj_do_bit17_swizzling &&
792 (page_to_phys(page) & (1 << 17)) != 0; 808 (page_to_phys(page) & (1 << 17)) != 0;
793 809
@@ -1633,6 +1649,7 @@ static void
1633i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) 1649i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
1634{ 1650{
1635 int page_count = obj->base.size / PAGE_SIZE; 1651 int page_count = obj->base.size / PAGE_SIZE;
1652 struct scatterlist *sg;
1636 int ret, i; 1653 int ret, i;
1637 1654
1638 BUG_ON(obj->madv == __I915_MADV_PURGED); 1655 BUG_ON(obj->madv == __I915_MADV_PURGED);
@@ -1653,19 +1670,21 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
1653 if (obj->madv == I915_MADV_DONTNEED) 1670 if (obj->madv == I915_MADV_DONTNEED)
1654 obj->dirty = 0; 1671 obj->dirty = 0;
1655 1672
1656 for (i = 0; i < page_count; i++) { 1673 for_each_sg(obj->pages->sgl, sg, page_count, i) {
1674 struct page *page = sg_page(sg);
1675
1657 if (obj->dirty) 1676 if (obj->dirty)
1658 set_page_dirty(obj->pages[i]); 1677 set_page_dirty(page);
1659 1678
1660 if (obj->madv == I915_MADV_WILLNEED) 1679 if (obj->madv == I915_MADV_WILLNEED)
1661 mark_page_accessed(obj->pages[i]); 1680 mark_page_accessed(page);
1662 1681
1663 page_cache_release(obj->pages[i]); 1682 page_cache_release(page);
1664 } 1683 }
1665 obj->dirty = 0; 1684 obj->dirty = 0;
1666 1685
1667 drm_free_large(obj->pages); 1686 sg_free_table(obj->pages);
1668 obj->pages = NULL; 1687 kfree(obj->pages);
1669} 1688}
1670 1689
1671static int 1690static int
@@ -1682,6 +1701,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
1682 return -EBUSY; 1701 return -EBUSY;
1683 1702
1684 ops->put_pages(obj); 1703 ops->put_pages(obj);
1704 obj->pages = NULL;
1685 1705
1686 list_del(&obj->gtt_list); 1706 list_del(&obj->gtt_list);
1687 if (i915_gem_object_is_purgeable(obj)) 1707 if (i915_gem_object_is_purgeable(obj))
@@ -1739,6 +1759,8 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
1739 struct drm_i915_private *dev_priv = obj->base.dev->dev_private; 1759 struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
1740 int page_count, i; 1760 int page_count, i;
1741 struct address_space *mapping; 1761 struct address_space *mapping;
1762 struct sg_table *st;
1763 struct scatterlist *sg;
1742 struct page *page; 1764 struct page *page;
1743 gfp_t gfp; 1765 gfp_t gfp;
1744 1766
@@ -1749,20 +1771,27 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
1749 BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); 1771 BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
1750 BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); 1772 BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
1751 1773
1752 /* Get the list of pages out of our struct file. They'll be pinned 1774 st = kmalloc(sizeof(*st), GFP_KERNEL);
1753 * at this point until we release them. 1775 if (st == NULL)
1754 */ 1776 return -ENOMEM;
1777
1755 page_count = obj->base.size / PAGE_SIZE; 1778 page_count = obj->base.size / PAGE_SIZE;
1756 obj->pages = drm_malloc_ab(page_count, sizeof(struct page *)); 1779 if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
1757 if (obj->pages == NULL) 1780 sg_free_table(st);
1781 kfree(st);
1758 return -ENOMEM; 1782 return -ENOMEM;
1783 }
1759 1784
1760 /* Fail silently without starting the shrinker */ 1785 /* Get the list of pages out of our struct file. They'll be pinned
1786 * at this point until we release them.
1787 *
1788 * Fail silently without starting the shrinker
1789 */
1761 mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; 1790 mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
1762 gfp = mapping_gfp_mask(mapping); 1791 gfp = mapping_gfp_mask(mapping);
1763 gfp |= __GFP_NORETRY | __GFP_NOWARN; 1792 gfp |= __GFP_NORETRY | __GFP_NOWARN;
1764 gfp &= ~(__GFP_IO | __GFP_WAIT); 1793 gfp &= ~(__GFP_IO | __GFP_WAIT);
1765 for (i = 0; i < page_count; i++) { 1794 for_each_sg(st->sgl, sg, page_count, i) {
1766 page = shmem_read_mapping_page_gfp(mapping, i, gfp); 1795 page = shmem_read_mapping_page_gfp(mapping, i, gfp);
1767 if (IS_ERR(page)) { 1796 if (IS_ERR(page)) {
1768 i915_gem_purge(dev_priv, page_count); 1797 i915_gem_purge(dev_priv, page_count);
@@ -1785,20 +1814,20 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
1785 gfp &= ~(__GFP_IO | __GFP_WAIT); 1814 gfp &= ~(__GFP_IO | __GFP_WAIT);
1786 } 1815 }
1787 1816
1788 obj->pages[i] = page; 1817 sg_set_page(sg, page, PAGE_SIZE, 0);
1789 } 1818 }
1790 1819
1791 if (i915_gem_object_needs_bit17_swizzle(obj)) 1820 if (i915_gem_object_needs_bit17_swizzle(obj))
1792 i915_gem_object_do_bit_17_swizzle(obj); 1821 i915_gem_object_do_bit_17_swizzle(obj);
1793 1822
1823 obj->pages = st;
1794 return 0; 1824 return 0;
1795 1825
1796err_pages: 1826err_pages:
1797 while (i--) 1827 for_each_sg(st->sgl, sg, i, page_count)
1798 page_cache_release(obj->pages[i]); 1828 page_cache_release(sg_page(sg));
1799 1829 sg_free_table(st);
1800 drm_free_large(obj->pages); 1830 kfree(st);
1801 obj->pages = NULL;
1802 return PTR_ERR(page); 1831 return PTR_ERR(page);
1803} 1832}
1804 1833
@@ -2981,7 +3010,7 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
2981 3010
2982 trace_i915_gem_object_clflush(obj); 3011 trace_i915_gem_object_clflush(obj);
2983 3012
2984 drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); 3013 drm_clflush_sg(obj->pages);
2985} 3014}
2986 3015
2987/** Flushes the GTT write domain for the object if it's dirty. */ 3016/** Flushes the GTT write domain for the object if it's dirty. */
@@ -3731,6 +3760,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
3731 i915_gem_object_put_pages(obj); 3760 i915_gem_object_put_pages(obj);
3732 i915_gem_object_free_mmap_offset(obj); 3761 i915_gem_object_free_mmap_offset(obj);
3733 3762
3763 BUG_ON(obj->pages);
3764
3734 drm_gem_object_release(&obj->base); 3765 drm_gem_object_release(&obj->base);
3735 i915_gem_info_remove_obj(dev_priv, obj->base.size); 3766 i915_gem_info_remove_obj(dev_priv, obj->base.size);
3736 3767