aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp
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/char/agp
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/char/agp')
-rw-r--r--drivers/char/agp/intel-gtt.c51
1 files changed, 22 insertions, 29 deletions
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 58e32f7c3229..7fa655ac24d8 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -84,40 +84,33 @@ static struct _intel_private {
84#define IS_IRONLAKE intel_private.driver->is_ironlake 84#define IS_IRONLAKE intel_private.driver->is_ironlake
85#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable 85#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable
86 86
87int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, 87static int intel_gtt_map_memory(struct page **pages,
88 struct scatterlist **sg_list, int *num_sg) 88 unsigned int num_entries,
89 struct sg_table *st)
89{ 90{
90 struct sg_table st;
91 struct scatterlist *sg; 91 struct scatterlist *sg;
92 int i; 92 int i;
93 93
94 if (*sg_list)
95 return 0; /* already mapped (for e.g. resume */
96
97 DBG("try mapping %lu pages\n", (unsigned long)num_entries); 94 DBG("try mapping %lu pages\n", (unsigned long)num_entries);
98 95
99 if (sg_alloc_table(&st, num_entries, GFP_KERNEL)) 96 if (sg_alloc_table(st, num_entries, GFP_KERNEL))
100 goto err; 97 goto err;
101 98
102 *sg_list = sg = st.sgl; 99 for_each_sg(st->sgl, sg, num_entries, i)
103
104 for (i = 0 ; i < num_entries; i++, sg = sg_next(sg))
105 sg_set_page(sg, pages[i], PAGE_SIZE, 0); 100 sg_set_page(sg, pages[i], PAGE_SIZE, 0);
106 101
107 *num_sg = pci_map_sg(intel_private.pcidev, *sg_list, 102 if (!pci_map_sg(intel_private.pcidev,
108 num_entries, PCI_DMA_BIDIRECTIONAL); 103 st->sgl, st->nents, PCI_DMA_BIDIRECTIONAL))
109 if (unlikely(!*num_sg))
110 goto err; 104 goto err;
111 105
112 return 0; 106 return 0;
113 107
114err: 108err:
115 sg_free_table(&st); 109 sg_free_table(st);
116 return -ENOMEM; 110 return -ENOMEM;
117} 111}
118EXPORT_SYMBOL(intel_gtt_map_memory);
119 112
120void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) 113static void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
121{ 114{
122 struct sg_table st; 115 struct sg_table st;
123 DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 116 DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
@@ -130,7 +123,6 @@ void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg)
130 123
131 sg_free_table(&st); 124 sg_free_table(&st);
132} 125}
133EXPORT_SYMBOL(intel_gtt_unmap_memory);
134 126
135static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 127static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
136{ 128{
@@ -879,8 +871,7 @@ static bool i830_check_flags(unsigned int flags)
879 return false; 871 return false;
880} 872}
881 873
882void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 874void intel_gtt_insert_sg_entries(struct sg_table *st,
883 unsigned int sg_len,
884 unsigned int pg_start, 875 unsigned int pg_start,
885 unsigned int flags) 876 unsigned int flags)
886{ 877{
@@ -892,12 +883,11 @@ void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
892 883
893 /* sg may merge pages, but we have to separate 884 /* sg may merge pages, but we have to separate
894 * per-page addr for GTT */ 885 * per-page addr for GTT */
895 for_each_sg(sg_list, sg, sg_len, i) { 886 for_each_sg(st->sgl, sg, st->nents, i) {
896 len = sg_dma_len(sg) >> PAGE_SHIFT; 887 len = sg_dma_len(sg) >> PAGE_SHIFT;
897 for (m = 0; m < len; m++) { 888 for (m = 0; m < len; m++) {
898 dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 889 dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
899 intel_private.driver->write_entry(addr, 890 intel_private.driver->write_entry(addr, j, flags);
900 j, flags);
901 j++; 891 j++;
902 } 892 }
903 } 893 }
@@ -905,8 +895,10 @@ void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
905} 895}
906EXPORT_SYMBOL(intel_gtt_insert_sg_entries); 896EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
907 897
908void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, 898static void intel_gtt_insert_pages(unsigned int first_entry,
909 struct page **pages, unsigned int flags) 899 unsigned int num_entries,
900 struct page **pages,
901 unsigned int flags)
910{ 902{
911 int i, j; 903 int i, j;
912 904
@@ -917,7 +909,6 @@ void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries,
917 } 909 }
918 readl(intel_private.gtt+j-1); 910 readl(intel_private.gtt+j-1);
919} 911}
920EXPORT_SYMBOL(intel_gtt_insert_pages);
921 912
922static int intel_fake_agp_insert_entries(struct agp_memory *mem, 913static int intel_fake_agp_insert_entries(struct agp_memory *mem,
923 off_t pg_start, int type) 914 off_t pg_start, int type)
@@ -953,13 +944,15 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
953 global_cache_flush(); 944 global_cache_flush();
954 945
955 if (intel_private.base.needs_dmar) { 946 if (intel_private.base.needs_dmar) {
956 ret = intel_gtt_map_memory(mem->pages, mem->page_count, 947 struct sg_table st;
957 &mem->sg_list, &mem->num_sg); 948
949 ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st);
958 if (ret != 0) 950 if (ret != 0)
959 return ret; 951 return ret;
960 952
961 intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 953 intel_gtt_insert_sg_entries(&st, pg_start, type);
962 pg_start, type); 954 mem->sg_list = st.sgl;
955 mem->num_sg = st.nents;
963 } else 956 } else
964 intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, 957 intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages,
965 type); 958 type);