aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/ttm/ttm_tt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/ttm/ttm_tt.c')
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c78
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 */
49static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm) 48static 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
64static void ttm_tt_free_page_directory(struct ttm_tt *ttm) 53static 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}
179EXPORT_SYMBOL(ttm_tt_populate);
195 180
196#ifdef CONFIG_X86 181#ifdef CONFIG_X86
197static inline int ttm_tt_set_page_caching(struct page *p, 182static 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 */
213static inline int ttm_tt_set_page_caching(struct page *p, 208static 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;
510out_err: 510out_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
515int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) 515int 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}