aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichel Dänzer <daenzer@vmware.com>2009-08-04 07:51:04 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-08-19 20:29:27 -0400
commite8a5f900148d058bce2d7bdce3d6bcbcb40267ec (patch)
tree7bac1787d09d25e7d1c054c62357b3afa6da0582 /drivers
parent52f072cb084bbb460d3a4ae09f0b6efc3e7e8a8c (diff)
agp/uninorth: Simplify cache flushing.
Map the GART table uncached, so we don't always need to flush the CPU caches explicitly after updates. Signed-off-by: Michel Dänzer <daenzer@vmware.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/agp/uninorth-agp.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 37ff3bd56d60..bba29abe917f 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -7,6 +7,7 @@
7#include <linux/pagemap.h> 7#include <linux/pagemap.h>
8#include <linux/agp_backend.h> 8#include <linux/agp_backend.h>
9#include <linux/delay.h> 9#include <linux/delay.h>
10#include <linux/vmalloc.h>
10#include <asm/uninorth.h> 11#include <asm/uninorth.h>
11#include <asm/pci-bridge.h> 12#include <asm/pci-bridge.h>
12#include <asm/prom.h> 13#include <asm/prom.h>
@@ -181,8 +182,6 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
181 } 182 }
182 (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]); 183 (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
183 mb(); 184 mb();
184 flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start],
185 (unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
186 185
187 uninorth_tlbflush(mem); 186 uninorth_tlbflush(mem);
188 return 0; 187 return 0;
@@ -226,7 +225,6 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
226 (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); 225 (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000);
227 } 226 }
228 mb(); 227 mb();
229 flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
230 uninorth_tlbflush(mem); 228 uninorth_tlbflush(mem);
231 229
232 return 0; 230 return 0;
@@ -245,7 +243,6 @@ int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
245 for (i = 0; i < mem->page_count; ++i) 243 for (i = 0; i < mem->page_count; ++i)
246 gp[i] = 0; 244 gp[i] = 0;
247 mb(); 245 mb();
248 flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
249 uninorth_tlbflush(mem); 246 uninorth_tlbflush(mem);
250 247
251 return 0; 248 return 0;
@@ -398,6 +395,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
398 int i; 395 int i;
399 void *temp; 396 void *temp;
400 struct page *page; 397 struct page *page;
398 struct page **pages;
401 399
402 /* We can't handle 2 level gatt's */ 400 /* We can't handle 2 level gatt's */
403 if (bridge->driver->size_type == LVL2_APER_SIZE) 401 if (bridge->driver->size_type == LVL2_APER_SIZE)
@@ -426,21 +424,39 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
426 if (table == NULL) 424 if (table == NULL)
427 return -ENOMEM; 425 return -ENOMEM;
428 426
427 pages = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL);
428 if (pages == NULL)
429 goto enomem;
430
429 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); 431 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
430 432
431 for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) 433 for (page = virt_to_page(table), i = 0; page <= virt_to_page(table_end);
434 page++, i++) {
432 SetPageReserved(page); 435 SetPageReserved(page);
436 pages[i] = page;
437 }
433 438
434 bridge->gatt_table_real = (u32 *) table; 439 bridge->gatt_table_real = (u32 *) table;
435 bridge->gatt_table = (u32 *)table; 440 /* Need to clear out any dirty data still sitting in caches */
441 flush_dcache_range((unsigned long)table,
442 (unsigned long)(table_end + PAGE_SIZE));
443 bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG);
444
445 if (bridge->gatt_table == NULL)
446 goto enomem;
447
436 bridge->gatt_bus_addr = virt_to_gart(table); 448 bridge->gatt_bus_addr = virt_to_gart(table);
437 449
438 for (i = 0; i < num_entries; i++) 450 for (i = 0; i < num_entries; i++)
439 bridge->gatt_table[i] = 0; 451 bridge->gatt_table[i] = 0;
440 452
441 flush_dcache_range((unsigned long)table, (unsigned long)table_end);
442
443 return 0; 453 return 0;
454
455enomem:
456 kfree(pages);
457 if (table)
458 free_pages((unsigned long)table, page_order);
459 return -ENOMEM;
444} 460}
445 461
446static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) 462static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
@@ -458,6 +474,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
458 * from the table. 474 * from the table.
459 */ 475 */
460 476
477 vunmap(bridge->gatt_table);
461 table = (char *) bridge->gatt_table_real; 478 table = (char *) bridge->gatt_table_real;
462 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); 479 table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
463 480