diff options
author | Dave Airlie <airlied@redhat.com> | 2009-06-12 00:11:41 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-06-18 20:21:42 -0400 |
commit | 07613ba2f464f59949266f4337b75b91eb610795 (patch) | |
tree | 8e43a82571686492aba2269c2e7a49c323783af1 /drivers/char/agp/i460-agp.c | |
parent | 2908826d045a89805714e0a3055a99dc40565d41 (diff) |
agp: switch AGP to use page array instead of unsigned long array
This switches AGP to use an array of pages for tracking the
pages allocated to the GART. This should enable GEM on PAE to work
a lot better as we can pass highmem pages to the PAT code and it will
do the right thing with them.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/char/agp/i460-agp.c')
-rw-r--r-- | drivers/char/agp/i460-agp.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 10da687d131a..60cc35bb5db7 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c | |||
@@ -60,6 +60,9 @@ | |||
60 | */ | 60 | */ |
61 | #define WR_FLUSH_GATT(index) RD_GATT(index) | 61 | #define WR_FLUSH_GATT(index) RD_GATT(index) |
62 | 62 | ||
63 | static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, | ||
64 | unsigned long addr, int type); | ||
65 | |||
63 | static struct { | 66 | static struct { |
64 | void *gatt; /* ioremap'd GATT area */ | 67 | void *gatt; /* ioremap'd GATT area */ |
65 | 68 | ||
@@ -74,6 +77,7 @@ static struct { | |||
74 | unsigned long *alloced_map; /* bitmap of kernel-pages in use */ | 77 | unsigned long *alloced_map; /* bitmap of kernel-pages in use */ |
75 | int refcount; /* number of kernel pages using the large page */ | 78 | int refcount; /* number of kernel pages using the large page */ |
76 | u64 paddr; /* physical address of large page */ | 79 | u64 paddr; /* physical address of large page */ |
80 | struct page *page; /* page pointer */ | ||
77 | } *lp_desc; | 81 | } *lp_desc; |
78 | } i460; | 82 | } i460; |
79 | 83 | ||
@@ -294,7 +298,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, | |||
294 | void *temp; | 298 | void *temp; |
295 | 299 | ||
296 | pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", | 300 | pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", |
297 | mem, pg_start, type, mem->memory[0]); | 301 | mem, pg_start, type, page_to_phys(mem->pages[0])); |
298 | 302 | ||
299 | if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) | 303 | if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) |
300 | return -EINVAL; | 304 | return -EINVAL; |
@@ -321,10 +325,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, | |||
321 | 325 | ||
322 | io_page_size = 1UL << I460_IO_PAGE_SHIFT; | 326 | io_page_size = 1UL << I460_IO_PAGE_SHIFT; |
323 | for (i = 0, j = io_pg_start; i < mem->page_count; i++) { | 327 | for (i = 0, j = io_pg_start; i < mem->page_count; i++) { |
324 | paddr = mem->memory[i]; | 328 | paddr = phys_to_gart(page_to_phys(mem->pages[i])); |
325 | for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size) | 329 | for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size) |
326 | WR_GATT(j, agp_bridge->driver->mask_memory(agp_bridge, | 330 | WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type)); |
327 | paddr, mem->type)); | ||
328 | } | 331 | } |
329 | WR_FLUSH_GATT(j - 1); | 332 | WR_FLUSH_GATT(j - 1); |
330 | return 0; | 333 | return 0; |
@@ -364,10 +367,9 @@ static int i460_alloc_large_page (struct lp_desc *lp) | |||
364 | { | 367 | { |
365 | unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT; | 368 | unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT; |
366 | size_t map_size; | 369 | size_t map_size; |
367 | void *lpage; | ||
368 | 370 | ||
369 | lpage = (void *) __get_free_pages(GFP_KERNEL, order); | 371 | lp->page = alloc_pages(GFP_KERNEL, order); |
370 | if (!lpage) { | 372 | if (!lp->page) { |
371 | printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); | 373 | printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); |
372 | return -ENOMEM; | 374 | return -ENOMEM; |
373 | } | 375 | } |
@@ -375,12 +377,12 @@ static int i460_alloc_large_page (struct lp_desc *lp) | |||
375 | map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; | 377 | map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; |
376 | lp->alloced_map = kzalloc(map_size, GFP_KERNEL); | 378 | lp->alloced_map = kzalloc(map_size, GFP_KERNEL); |
377 | if (!lp->alloced_map) { | 379 | if (!lp->alloced_map) { |
378 | free_pages((unsigned long) lpage, order); | 380 | __free_pages(lp->page, order); |
379 | printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); | 381 | printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); |
380 | return -ENOMEM; | 382 | return -ENOMEM; |
381 | } | 383 | } |
382 | 384 | ||
383 | lp->paddr = virt_to_gart(lpage); | 385 | lp->paddr = phys_to_gart(page_to_phys(lp->page)); |
384 | lp->refcount = 0; | 386 | lp->refcount = 0; |
385 | atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); | 387 | atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); |
386 | return 0; | 388 | return 0; |
@@ -391,7 +393,7 @@ static void i460_free_large_page (struct lp_desc *lp) | |||
391 | kfree(lp->alloced_map); | 393 | kfree(lp->alloced_map); |
392 | lp->alloced_map = NULL; | 394 | lp->alloced_map = NULL; |
393 | 395 | ||
394 | free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); | 396 | __free_pages(lp->page, I460_IO_PAGE_SHIFT - PAGE_SHIFT); |
395 | atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); | 397 | atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); |
396 | } | 398 | } |
397 | 399 | ||
@@ -439,8 +441,8 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, | |||
439 | if (i460_alloc_large_page(lp) < 0) | 441 | if (i460_alloc_large_page(lp) < 0) |
440 | return -ENOMEM; | 442 | return -ENOMEM; |
441 | pg = lp - i460.lp_desc; | 443 | pg = lp - i460.lp_desc; |
442 | WR_GATT(pg, agp_bridge->driver->mask_memory(agp_bridge, | 444 | WR_GATT(pg, i460_mask_memory(agp_bridge, |
443 | lp->paddr, 0)); | 445 | lp->paddr, 0)); |
444 | WR_FLUSH_GATT(pg); | 446 | WR_FLUSH_GATT(pg); |
445 | } | 447 | } |
446 | 448 | ||
@@ -448,7 +450,7 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, | |||
448 | idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); | 450 | idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); |
449 | idx++, i++) | 451 | idx++, i++) |
450 | { | 452 | { |
451 | mem->memory[i] = lp->paddr + idx*PAGE_SIZE; | 453 | mem->pages[i] = lp->page; |
452 | __set_bit(idx, lp->alloced_map); | 454 | __set_bit(idx, lp->alloced_map); |
453 | ++lp->refcount; | 455 | ++lp->refcount; |
454 | } | 456 | } |
@@ -463,7 +465,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, | |||
463 | struct lp_desc *start, *end, *lp; | 465 | struct lp_desc *start, *end, *lp; |
464 | void *temp; | 466 | void *temp; |
465 | 467 | ||
466 | temp = agp_bridge->driver->current_size; | 468 | temp = agp_bridge->current_size; |
467 | num_entries = A_SIZE_8(temp)->num_entries; | 469 | num_entries = A_SIZE_8(temp)->num_entries; |
468 | 470 | ||
469 | /* Figure out what pg_start means in terms of our large GART pages */ | 471 | /* Figure out what pg_start means in terms of our large GART pages */ |
@@ -477,7 +479,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, | |||
477 | idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); | 479 | idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); |
478 | idx++, i++) | 480 | idx++, i++) |
479 | { | 481 | { |
480 | mem->memory[i] = 0; | 482 | mem->pages[i] = NULL; |
481 | __clear_bit(idx, lp->alloced_map); | 483 | __clear_bit(idx, lp->alloced_map); |
482 | --lp->refcount; | 484 | --lp->refcount; |
483 | } | 485 | } |
@@ -521,7 +523,7 @@ static int i460_remove_memory (struct agp_memory *mem, | |||
521 | * Let's just hope nobody counts on the allocated AGP memory being there before bind time | 523 | * Let's just hope nobody counts on the allocated AGP memory being there before bind time |
522 | * (I don't think current drivers do)... | 524 | * (I don't think current drivers do)... |
523 | */ | 525 | */ |
524 | static void *i460_alloc_page (struct agp_bridge_data *bridge) | 526 | static struct page *i460_alloc_page (struct agp_bridge_data *bridge) |
525 | { | 527 | { |
526 | void *page; | 528 | void *page; |
527 | 529 | ||
@@ -534,7 +536,7 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) | |||
534 | return page; | 536 | return page; |
535 | } | 537 | } |
536 | 538 | ||
537 | static void i460_destroy_page (void *page, int flags) | 539 | static void i460_destroy_page (struct page *page, int flags) |
538 | { | 540 | { |
539 | if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { | 541 | if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { |
540 | agp_generic_destroy_page(page, flags); | 542 | agp_generic_destroy_page(page, flags); |
@@ -544,13 +546,20 @@ static void i460_destroy_page (void *page, int flags) | |||
544 | #endif /* I460_LARGE_IO_PAGES */ | 546 | #endif /* I460_LARGE_IO_PAGES */ |
545 | 547 | ||
546 | static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, | 548 | static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, |
547 | unsigned long addr, int type) | 549 | unsigned long addr, int type) |
548 | { | 550 | { |
549 | /* Make sure the returned address is a valid GATT entry */ | 551 | /* Make sure the returned address is a valid GATT entry */ |
550 | return bridge->driver->masks[0].mask | 552 | return bridge->driver->masks[0].mask |
551 | | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12); | 553 | | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12); |
552 | } | 554 | } |
553 | 555 | ||
556 | static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge, | ||
557 | struct page *page, int type) | ||
558 | { | ||
559 | unsigned long addr = phys_to_gart(page_to_phys(page)); | ||
560 | return i460_mask_memory(bridge, addr, type); | ||
561 | } | ||
562 | |||
554 | const struct agp_bridge_driver intel_i460_driver = { | 563 | const struct agp_bridge_driver intel_i460_driver = { |
555 | .owner = THIS_MODULE, | 564 | .owner = THIS_MODULE, |
556 | .aperture_sizes = i460_sizes, | 565 | .aperture_sizes = i460_sizes, |
@@ -560,7 +569,7 @@ const struct agp_bridge_driver intel_i460_driver = { | |||
560 | .fetch_size = i460_fetch_size, | 569 | .fetch_size = i460_fetch_size, |
561 | .cleanup = i460_cleanup, | 570 | .cleanup = i460_cleanup, |
562 | .tlb_flush = i460_tlb_flush, | 571 | .tlb_flush = i460_tlb_flush, |
563 | .mask_memory = i460_mask_memory, | 572 | .mask_memory = i460_page_mask_memory, |
564 | .masks = i460_masks, | 573 | .masks = i460_masks, |
565 | .agp_enable = agp_generic_enable, | 574 | .agp_enable = agp_generic_enable, |
566 | .cache_flush = global_cache_flush, | 575 | .cache_flush = global_cache_flush, |