diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 146 |
4 files changed, 167 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 03a9e49fe93d..35c8b5316396 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -850,6 +850,8 @@ struct drm_i915_gem_object { | |||
850 | 850 | ||
851 | unsigned int cache_level:2; | 851 | unsigned int cache_level:2; |
852 | 852 | ||
853 | unsigned int has_aliasing_ppgtt_mapping:1; | ||
854 | |||
853 | struct page **pages; | 855 | struct page **pages; |
854 | 856 | ||
855 | /** | 857 | /** |
@@ -1249,6 +1251,11 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, | |||
1249 | /* i915_gem_gtt.c */ | 1251 | /* i915_gem_gtt.c */ |
1250 | int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); | 1252 | int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); |
1251 | void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); | 1253 | void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); |
1254 | void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, | ||
1255 | struct drm_i915_gem_object *obj, | ||
1256 | enum i915_cache_level cache_level); | ||
1257 | void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, | ||
1258 | struct drm_i915_gem_object *obj); | ||
1252 | 1259 | ||
1253 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); | 1260 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); |
1254 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); | 1261 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 27fe07a2fd33..59092997bcfb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -2020,6 +2020,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) | |||
2020 | int | 2020 | int |
2021 | i915_gem_object_unbind(struct drm_i915_gem_object *obj) | 2021 | i915_gem_object_unbind(struct drm_i915_gem_object *obj) |
2022 | { | 2022 | { |
2023 | drm_i915_private_t *dev_priv = obj->base.dev->dev_private; | ||
2023 | int ret = 0; | 2024 | int ret = 0; |
2024 | 2025 | ||
2025 | if (obj->gtt_space == NULL) | 2026 | if (obj->gtt_space == NULL) |
@@ -2064,6 +2065,11 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) | |||
2064 | trace_i915_gem_object_unbind(obj); | 2065 | trace_i915_gem_object_unbind(obj); |
2065 | 2066 | ||
2066 | i915_gem_gtt_unbind_object(obj); | 2067 | i915_gem_gtt_unbind_object(obj); |
2068 | if (obj->has_aliasing_ppgtt_mapping) { | ||
2069 | i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj); | ||
2070 | obj->has_aliasing_ppgtt_mapping = 0; | ||
2071 | } | ||
2072 | |||
2067 | i915_gem_object_put_pages_gtt(obj); | 2073 | i915_gem_object_put_pages_gtt(obj); |
2068 | 2074 | ||
2069 | list_del_init(&obj->gtt_list); | 2075 | list_del_init(&obj->gtt_list); |
@@ -2882,6 +2888,8 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) | |||
2882 | int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, | 2888 | int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, |
2883 | enum i915_cache_level cache_level) | 2889 | enum i915_cache_level cache_level) |
2884 | { | 2890 | { |
2891 | struct drm_device *dev = obj->base.dev; | ||
2892 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
2885 | int ret; | 2893 | int ret; |
2886 | 2894 | ||
2887 | if (obj->cache_level == cache_level) | 2895 | if (obj->cache_level == cache_level) |
@@ -2910,6 +2918,9 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, | |||
2910 | } | 2918 | } |
2911 | 2919 | ||
2912 | i915_gem_gtt_rebind_object(obj, cache_level); | 2920 | i915_gem_gtt_rebind_object(obj, cache_level); |
2921 | if (obj->has_aliasing_ppgtt_mapping) | ||
2922 | i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, | ||
2923 | obj, cache_level); | ||
2913 | } | 2924 | } |
2914 | 2925 | ||
2915 | if (cache_level == I915_CACHE_NONE) { | 2926 | if (cache_level == I915_CACHE_NONE) { |
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index b964998b5e25..9835b2efd93e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c | |||
@@ -515,6 +515,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
515 | struct drm_file *file, | 515 | struct drm_file *file, |
516 | struct list_head *objects) | 516 | struct list_head *objects) |
517 | { | 517 | { |
518 | drm_i915_private_t *dev_priv = ring->dev->dev_private; | ||
518 | struct drm_i915_gem_object *obj; | 519 | struct drm_i915_gem_object *obj; |
519 | int ret, retry; | 520 | int ret, retry; |
520 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; | 521 | bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4; |
@@ -623,6 +624,14 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | |||
623 | } | 624 | } |
624 | 625 | ||
625 | i915_gem_object_unpin(obj); | 626 | i915_gem_object_unpin(obj); |
627 | |||
628 | /* ... and ensure ppgtt mapping exist if needed. */ | ||
629 | if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) { | ||
630 | i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, | ||
631 | obj, obj->cache_level); | ||
632 | |||
633 | obj->has_aliasing_ppgtt_mapping = 1; | ||
634 | } | ||
626 | } | 635 | } |
627 | 636 | ||
628 | if (ret != -ENOSPC || retry > 1) | 637 | if (ret != -ENOSPC || retry > 1) |
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f408f8c710db..2eacd78bb93b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c | |||
@@ -34,22 +34,31 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | |||
34 | unsigned first_entry, | 34 | unsigned first_entry, |
35 | unsigned num_entries) | 35 | unsigned num_entries) |
36 | { | 36 | { |
37 | int i, j; | ||
38 | uint32_t *pt_vaddr; | 37 | uint32_t *pt_vaddr; |
39 | uint32_t scratch_pte; | 38 | uint32_t scratch_pte; |
39 | unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; | ||
40 | unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | ||
41 | unsigned last_pte, i; | ||
40 | 42 | ||
41 | scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr); | 43 | scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr); |
42 | scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC; | 44 | scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC; |
43 | 45 | ||
44 | for (i = 0; i < ppgtt->num_pd_entries; i++) { | 46 | while (num_entries) { |
45 | pt_vaddr = kmap_atomic(ppgtt->pt_pages[i]); | 47 | last_pte = first_pte + num_entries; |
48 | if (last_pte > I915_PPGTT_PT_ENTRIES) | ||
49 | last_pte = I915_PPGTT_PT_ENTRIES; | ||
50 | |||
51 | pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); | ||
46 | 52 | ||
47 | for (j = 0; j < I915_PPGTT_PT_ENTRIES; j++) | 53 | for (i = first_pte; i < last_pte; i++) |
48 | pt_vaddr[j] = scratch_pte; | 54 | pt_vaddr[i] = scratch_pte; |
49 | 55 | ||
50 | kunmap_atomic(pt_vaddr); | 56 | kunmap_atomic(pt_vaddr); |
51 | } | ||
52 | 57 | ||
58 | num_entries -= last_pte - first_pte; | ||
59 | first_pte = 0; | ||
60 | act_pd++; | ||
61 | } | ||
53 | } | 62 | } |
54 | 63 | ||
55 | int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) | 64 | int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) |
@@ -168,6 +177,131 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) | |||
168 | kfree(ppgtt); | 177 | kfree(ppgtt); |
169 | } | 178 | } |
170 | 179 | ||
180 | static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, | ||
181 | struct scatterlist *sg_list, | ||
182 | unsigned sg_len, | ||
183 | unsigned first_entry, | ||
184 | uint32_t pte_flags) | ||
185 | { | ||
186 | uint32_t *pt_vaddr, pte; | ||
187 | unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; | ||
188 | unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | ||
189 | unsigned i, j, m, segment_len; | ||
190 | dma_addr_t page_addr; | ||
191 | struct scatterlist *sg; | ||
192 | |||
193 | /* init sg walking */ | ||
194 | sg = sg_list; | ||
195 | i = 0; | ||
196 | segment_len = sg_dma_len(sg) >> PAGE_SHIFT; | ||
197 | m = 0; | ||
198 | |||
199 | while (i < sg_len) { | ||
200 | pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); | ||
201 | |||
202 | for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { | ||
203 | page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); | ||
204 | pte = GEN6_PTE_ADDR_ENCODE(page_addr); | ||
205 | pt_vaddr[j] = pte | pte_flags; | ||
206 | |||
207 | /* grab the next page */ | ||
208 | m++; | ||
209 | if (m == segment_len) { | ||
210 | sg = sg_next(sg); | ||
211 | i++; | ||
212 | if (i == sg_len) | ||
213 | break; | ||
214 | |||
215 | segment_len = sg_dma_len(sg) >> PAGE_SHIFT; | ||
216 | m = 0; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | kunmap_atomic(pt_vaddr); | ||
221 | |||
222 | first_pte = 0; | ||
223 | act_pd++; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, | ||
228 | unsigned first_entry, unsigned num_entries, | ||
229 | struct page **pages, uint32_t pte_flags) | ||
230 | { | ||
231 | uint32_t *pt_vaddr, pte; | ||
232 | unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; | ||
233 | unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | ||
234 | unsigned last_pte, i; | ||
235 | dma_addr_t page_addr; | ||
236 | |||
237 | while (num_entries) { | ||
238 | last_pte = first_pte + num_entries; | ||
239 | last_pte = min_t(unsigned, last_pte, I915_PPGTT_PT_ENTRIES); | ||
240 | |||
241 | pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); | ||
242 | |||
243 | for (i = first_pte; i < last_pte; i++) { | ||
244 | page_addr = page_to_phys(*pages); | ||
245 | pte = GEN6_PTE_ADDR_ENCODE(page_addr); | ||
246 | pt_vaddr[i] = pte | pte_flags; | ||
247 | |||
248 | pages++; | ||
249 | } | ||
250 | |||
251 | kunmap_atomic(pt_vaddr); | ||
252 | |||
253 | num_entries -= last_pte - first_pte; | ||
254 | first_pte = 0; | ||
255 | act_pd++; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, | ||
260 | struct drm_i915_gem_object *obj, | ||
261 | enum i915_cache_level cache_level) | ||
262 | { | ||
263 | struct drm_device *dev = obj->base.dev; | ||
264 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
265 | uint32_t pte_flags = GEN6_PTE_VALID; | ||
266 | |||
267 | switch (cache_level) { | ||
268 | case I915_CACHE_LLC_MLC: | ||
269 | pte_flags |= GEN6_PTE_CACHE_LLC_MLC; | ||
270 | break; | ||
271 | case I915_CACHE_LLC: | ||
272 | pte_flags |= GEN6_PTE_CACHE_LLC; | ||
273 | break; | ||
274 | case I915_CACHE_NONE: | ||
275 | pte_flags |= GEN6_PTE_UNCACHED; | ||
276 | break; | ||
277 | default: | ||
278 | BUG(); | ||
279 | } | ||
280 | |||
281 | if (dev_priv->mm.gtt->needs_dmar) { | ||
282 | BUG_ON(!obj->sg_list); | ||
283 | |||
284 | i915_ppgtt_insert_sg_entries(ppgtt, | ||
285 | obj->sg_list, | ||
286 | obj->num_sg, | ||
287 | obj->gtt_space->start >> PAGE_SHIFT, | ||
288 | pte_flags); | ||
289 | } else | ||
290 | i915_ppgtt_insert_pages(ppgtt, | ||
291 | obj->gtt_space->start >> PAGE_SHIFT, | ||
292 | obj->base.size >> PAGE_SHIFT, | ||
293 | obj->pages, | ||
294 | pte_flags); | ||
295 | } | ||
296 | |||
297 | void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, | ||
298 | struct drm_i915_gem_object *obj) | ||
299 | { | ||
300 | i915_ppgtt_clear_range(ppgtt, | ||
301 | obj->gtt_space->start >> PAGE_SHIFT, | ||
302 | obj->base.size >> PAGE_SHIFT); | ||
303 | } | ||
304 | |||
171 | /* XXX kill agp_type! */ | 305 | /* XXX kill agp_type! */ |
172 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, | 306 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, |
173 | enum i915_cache_level cache_level) | 307 | enum i915_cache_level cache_level) |