diff options
Diffstat (limited to 'drivers/gpu/drm/ttm/ttm_tt.c')
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_tt.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 7bcb89f39ce8..d5fd5b8faeb3 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c | |||
@@ -28,13 +28,14 @@ | |||
28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> | 28 | * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/vmalloc.h> | ||
32 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
33 | #include <linux/highmem.h> | 32 | #include <linux/highmem.h> |
34 | #include <linux/pagemap.h> | 33 | #include <linux/pagemap.h> |
35 | #include <linux/file.h> | 34 | #include <linux/file.h> |
36 | #include <linux/swap.h> | 35 | #include <linux/swap.h> |
36 | #include <linux/slab.h> | ||
37 | #include "drm_cache.h" | 37 | #include "drm_cache.h" |
38 | #include "drm_mem_util.h" | ||
38 | #include "ttm/ttm_module.h" | 39 | #include "ttm/ttm_module.h" |
39 | #include "ttm/ttm_bo_driver.h" | 40 | #include "ttm/ttm_bo_driver.h" |
40 | #include "ttm/ttm_placement.h" | 41 | #include "ttm/ttm_placement.h" |
@@ -43,32 +44,15 @@ static int ttm_tt_swapin(struct ttm_tt *ttm); | |||
43 | 44 | ||
44 | /** | 45 | /** |
45 | * Allocates storage for pointers to the pages that back the ttm. | 46 | * Allocates storage for pointers to the pages that back the ttm. |
46 | * | ||
47 | * Uses kmalloc if possible. Otherwise falls back to vmalloc. | ||
48 | */ | 47 | */ |
49 | static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) | 48 | static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) |
50 | { | 49 | { |
51 | unsigned long size = ttm->num_pages * sizeof(*ttm->pages); | 50 | ttm->pages = drm_calloc_large(ttm->num_pages, sizeof(*ttm->pages)); |
52 | ttm->pages = NULL; | ||
53 | |||
54 | if (size <= PAGE_SIZE) | ||
55 | ttm->pages = kzalloc(size, GFP_KERNEL); | ||
56 | |||
57 | if (!ttm->pages) { | ||
58 | ttm->pages = vmalloc_user(size); | ||
59 | if (ttm->pages) | ||
60 | ttm->page_flags |= TTM_PAGE_FLAG_VMALLOC; | ||
61 | } | ||
62 | } | 51 | } |
63 | 52 | ||
64 | static void ttm_tt_free_page_directory(struct ttm_tt *ttm) | 53 | static void ttm_tt_free_page_directory(struct ttm_tt *ttm) |
65 | { | 54 | { |
66 | if (ttm->page_flags & TTM_PAGE_FLAG_VMALLOC) { | 55 | drm_free_large(ttm->pages); |
67 | vfree(ttm->pages); | ||
68 | ttm->page_flags &= ~TTM_PAGE_FLAG_VMALLOC; | ||
69 | } else { | ||
70 | kfree(ttm->pages); | ||
71 | } | ||
72 | ttm->pages = NULL; | 56 | ttm->pages = NULL; |
73 | } | 57 | } |
74 | 58 | ||
@@ -192,26 +176,38 @@ int ttm_tt_populate(struct ttm_tt *ttm) | |||
192 | ttm->state = tt_unbound; | 176 | ttm->state = tt_unbound; |
193 | return 0; | 177 | return 0; |
194 | } | 178 | } |
179 | EXPORT_SYMBOL(ttm_tt_populate); | ||
195 | 180 | ||
196 | #ifdef CONFIG_X86 | 181 | #ifdef CONFIG_X86 |
197 | static inline int ttm_tt_set_page_caching(struct page *p, | 182 | static inline int ttm_tt_set_page_caching(struct page *p, |
198 | enum ttm_caching_state c_state) | 183 | enum ttm_caching_state c_old, |
184 | enum ttm_caching_state c_new) | ||
199 | { | 185 | { |
186 | int ret = 0; | ||
187 | |||
200 | if (PageHighMem(p)) | 188 | if (PageHighMem(p)) |
201 | return 0; | 189 | return 0; |
202 | 190 | ||
203 | switch (c_state) { | 191 | if (c_old != tt_cached) { |
204 | case tt_cached: | 192 | /* p isn't in the default caching state, set it to |
205 | return set_pages_wb(p, 1); | 193 | * writeback first to free its current memtype. */ |
206 | case tt_wc: | 194 | |
207 | return set_memory_wc((unsigned long) page_address(p), 1); | 195 | ret = set_pages_wb(p, 1); |
208 | default: | 196 | if (ret) |
209 | return set_pages_uc(p, 1); | 197 | return ret; |
210 | } | 198 | } |
199 | |||
200 | if (c_new == tt_wc) | ||
201 | ret = set_memory_wc((unsigned long) page_address(p), 1); | ||
202 | else if (c_new == tt_uncached) | ||
203 | ret = set_pages_uc(p, 1); | ||
204 | |||
205 | return ret; | ||
211 | } | 206 | } |
212 | #else /* CONFIG_X86 */ | 207 | #else /* CONFIG_X86 */ |
213 | static inline int ttm_tt_set_page_caching(struct page *p, | 208 | static inline int ttm_tt_set_page_caching(struct page *p, |
214 | enum ttm_caching_state c_state) | 209 | enum ttm_caching_state c_old, |
210 | enum ttm_caching_state c_new) | ||
215 | { | 211 | { |
216 | return 0; | 212 | return 0; |
217 | } | 213 | } |
@@ -244,7 +240,9 @@ static int ttm_tt_set_caching(struct ttm_tt *ttm, | |||
244 | for (i = 0; i < ttm->num_pages; ++i) { | 240 | for (i = 0; i < ttm->num_pages; ++i) { |
245 | cur_page = ttm->pages[i]; | 241 | cur_page = ttm->pages[i]; |
246 | if (likely(cur_page != NULL)) { | 242 | if (likely(cur_page != NULL)) { |
247 | ret = ttm_tt_set_page_caching(cur_page, c_state); | 243 | ret = ttm_tt_set_page_caching(cur_page, |
244 | ttm->caching_state, | ||
245 | c_state); | ||
248 | if (unlikely(ret != 0)) | 246 | if (unlikely(ret != 0)) |
249 | goto out_err; | 247 | goto out_err; |
250 | } | 248 | } |
@@ -258,7 +256,7 @@ out_err: | |||
258 | for (j = 0; j < i; ++j) { | 256 | for (j = 0; j < i; ++j) { |
259 | cur_page = ttm->pages[j]; | 257 | cur_page = ttm->pages[j]; |
260 | if (likely(cur_page != NULL)) { | 258 | if (likely(cur_page != NULL)) { |
261 | (void)ttm_tt_set_page_caching(cur_page, | 259 | (void)ttm_tt_set_page_caching(cur_page, c_state, |
262 | ttm->caching_state); | 260 | ttm->caching_state); |
263 | } | 261 | } |
264 | } | 262 | } |
@@ -466,7 +464,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm) | |||
466 | void *from_virtual; | 464 | void *from_virtual; |
467 | void *to_virtual; | 465 | void *to_virtual; |
468 | int i; | 466 | int i; |
469 | int ret; | 467 | int ret = -ENOMEM; |
470 | 468 | ||
471 | if (ttm->page_flags & TTM_PAGE_FLAG_USER) { | 469 | if (ttm->page_flags & TTM_PAGE_FLAG_USER) { |
472 | ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start, | 470 | ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start, |
@@ -485,8 +483,10 @@ static int ttm_tt_swapin(struct ttm_tt *ttm) | |||
485 | 483 | ||
486 | for (i = 0; i < ttm->num_pages; ++i) { | 484 | for (i = 0; i < ttm->num_pages; ++i) { |
487 | from_page = read_mapping_page(swap_space, i, NULL); | 485 | from_page = read_mapping_page(swap_space, i, NULL); |
488 | if (IS_ERR(from_page)) | 486 | if (IS_ERR(from_page)) { |
487 | ret = PTR_ERR(from_page); | ||
489 | goto out_err; | 488 | goto out_err; |
489 | } | ||
490 | to_page = __ttm_tt_get_page(ttm, i); | 490 | to_page = __ttm_tt_get_page(ttm, i); |
491 | if (unlikely(to_page == NULL)) | 491 | if (unlikely(to_page == NULL)) |
492 | goto out_err; | 492 | goto out_err; |
@@ -509,7 +509,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm) | |||
509 | return 0; | 509 | return 0; |
510 | out_err: | 510 | out_err: |
511 | ttm_tt_free_alloced_pages(ttm); | 511 | ttm_tt_free_alloced_pages(ttm); |
512 | return -ENOMEM; | 512 | return ret; |
513 | } | 513 | } |
514 | 514 | ||
515 | int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) | 515 | int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) |
@@ -521,6 +521,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) | |||
521 | void *from_virtual; | 521 | void *from_virtual; |
522 | void *to_virtual; | 522 | void *to_virtual; |
523 | int i; | 523 | int i; |
524 | int ret = -ENOMEM; | ||
524 | 525 | ||
525 | BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated); | 526 | BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated); |
526 | BUG_ON(ttm->caching_state != tt_cached); | 527 | BUG_ON(ttm->caching_state != tt_cached); |
@@ -543,7 +544,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) | |||
543 | 0); | 544 | 0); |
544 | if (unlikely(IS_ERR(swap_storage))) { | 545 | if (unlikely(IS_ERR(swap_storage))) { |
545 | printk(KERN_ERR "Failed allocating swap storage.\n"); | 546 | printk(KERN_ERR "Failed allocating swap storage.\n"); |
546 | return -ENOMEM; | 547 | return PTR_ERR(swap_storage); |
547 | } | 548 | } |
548 | } else | 549 | } else |
549 | swap_storage = persistant_swap_storage; | 550 | swap_storage = persistant_swap_storage; |
@@ -555,9 +556,10 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) | |||
555 | if (unlikely(from_page == NULL)) | 556 | if (unlikely(from_page == NULL)) |
556 | continue; | 557 | continue; |
557 | to_page = read_mapping_page(swap_space, i, NULL); | 558 | to_page = read_mapping_page(swap_space, i, NULL); |
558 | if (unlikely(to_page == NULL)) | 559 | if (unlikely(IS_ERR(to_page))) { |
560 | ret = PTR_ERR(to_page); | ||
559 | goto out_err; | 561 | goto out_err; |
560 | 562 | } | |
561 | preempt_disable(); | 563 | preempt_disable(); |
562 | from_virtual = kmap_atomic(from_page, KM_USER0); | 564 | from_virtual = kmap_atomic(from_page, KM_USER0); |
563 | to_virtual = kmap_atomic(to_page, KM_USER1); | 565 | to_virtual = kmap_atomic(to_page, KM_USER1); |
@@ -581,5 +583,5 @@ out_err: | |||
581 | if (!persistant_swap_storage) | 583 | if (!persistant_swap_storage) |
582 | fput(swap_storage); | 584 | fput(swap_storage); |
583 | 585 | ||
584 | return -ENOMEM; | 586 | return ret; |
585 | } | 587 | } |