diff options
author | Michel Dänzer <daenzer@vmware.com> | 2009-08-04 07:51:04 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-08-19 20:29:27 -0400 |
commit | e8a5f900148d058bce2d7bdce3d6bcbcb40267ec (patch) | |
tree | 7bac1787d09d25e7d1c054c62357b3afa6da0582 /drivers | |
parent | 52f072cb084bbb460d3a4ae09f0b6efc3e7e8a8c (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.c | 33 |
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 | |||
455 | enomem: | ||
456 | kfree(pages); | ||
457 | if (table) | ||
458 | free_pages((unsigned long)table, page_order); | ||
459 | return -ENOMEM; | ||
444 | } | 460 | } |
445 | 461 | ||
446 | static int uninorth_free_gatt_table(struct agp_bridge_data *bridge) | 462 | static 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 | ||