aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/i460-agp.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-06-12 00:11:41 -0400
committerDave Airlie <airlied@redhat.com>2009-06-18 20:21:42 -0400
commit07613ba2f464f59949266f4337b75b91eb610795 (patch)
tree8e43a82571686492aba2269c2e7a49c323783af1 /drivers/char/agp/i460-agp.c
parent2908826d045a89805714e0a3055a99dc40565d41 (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.c47
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
63static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
64 unsigned long addr, int type);
65
63static struct { 66static 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 */
524static void *i460_alloc_page (struct agp_bridge_data *bridge) 526static 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
537static void i460_destroy_page (void *page, int flags) 539static 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
546static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, 548static 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
556static 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
554const struct agp_bridge_driver intel_i460_driver = { 563const 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,