aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorAlan Hourihane <alanh@fairlite.demon.co.uk>2005-11-07 02:35:34 -0500
committerDave Jones <davej@redhat.com>2005-11-08 16:43:54 -0500
commit88d51967f56f55a45849efe50858ea7dfa0d38dc (patch)
tree048db8e12c2b31ec2b88c3154da4c6a77b80028c /drivers/char
parent329f7dba5f7dc3bc9a30ad00cf373d2e83115aa1 (diff)
[PATCH] AGP performance fixes
AGP allocation/deallocation is suffering major performance issues due to the nature of global_flush_tlb() being called on every change_page_attr() call. For small allocations this isn't really seen, but when you start allocating 50000 pages of AGP space, for say, texture memory, then things can take seconds to complete. In some cases the situation is doubled or even quadrupled in the time due to SMP, or a deallocation, then a new reallocation. I've had a case of upto 20 seconds wait time to deallocate and reallocate AGP space. This patch fixes the problem by making it the caller's responsibility to call global_flush_tlb(), and so removes it from every instance of mapping a page into AGP space until the time that all change_page_attr() changes are done. Signed-off-by: Dave Jones <davej@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/agp/backend.c9
-rw-r--r--drivers/char/agp/generic.c11
-rw-r--r--drivers/char/agp/i460-agp.c9
-rw-r--r--drivers/char/agp/intel-agp.c5
4 files changed, 25 insertions, 9 deletions
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 73f333f491bd..4d5ed18dad00 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -147,6 +147,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
147 printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); 147 printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
148 return -ENOMEM; 148 return -ENOMEM;
149 } 149 }
150 global_flush_tlb();
150 151
151 bridge->scratch_page_real = virt_to_gart(addr); 152 bridge->scratch_page_real = virt_to_gart(addr);
152 bridge->scratch_page = 153 bridge->scratch_page =
@@ -187,9 +188,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
187 return 0; 188 return 0;
188 189
189err_out: 190err_out:
190 if (bridge->driver->needs_scratch_page) 191 if (bridge->driver->needs_scratch_page) {
191 bridge->driver->agp_destroy_page( 192 bridge->driver->agp_destroy_page(
192 gart_to_virt(bridge->scratch_page_real)); 193 gart_to_virt(bridge->scratch_page_real));
194 global_flush_tlb();
195 }
193 if (got_gatt) 196 if (got_gatt)
194 bridge->driver->free_gatt_table(bridge); 197 bridge->driver->free_gatt_table(bridge);
195 if (got_keylist) { 198 if (got_keylist) {
@@ -211,9 +214,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
211 bridge->key_list = NULL; 214 bridge->key_list = NULL;
212 215
213 if (bridge->driver->agp_destroy_page && 216 if (bridge->driver->agp_destroy_page &&
214 bridge->driver->needs_scratch_page) 217 bridge->driver->needs_scratch_page) {
215 bridge->driver->agp_destroy_page( 218 bridge->driver->agp_destroy_page(
216 gart_to_virt(bridge->scratch_page_real)); 219 gart_to_virt(bridge->scratch_page_real));
220 global_flush_tlb();
221 }
217} 222}
218 223
219/* When we remove the global variable agp_bridge from all drivers 224/* When we remove the global variable agp_bridge from all drivers
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index c4a38715c6f9..19f242b50781 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -57,7 +57,8 @@ int map_page_into_agp(struct page *page)
57{ 57{
58 int i; 58 int i;
59 i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); 59 i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
60 global_flush_tlb(); 60 /* Caller's responsibility to call global_flush_tlb() for
61 * performance reasons */
61 return i; 62 return i;
62} 63}
63EXPORT_SYMBOL_GPL(map_page_into_agp); 64EXPORT_SYMBOL_GPL(map_page_into_agp);
@@ -66,7 +67,8 @@ int unmap_page_from_agp(struct page *page)
66{ 67{
67 int i; 68 int i;
68 i = change_page_attr(page, 1, PAGE_KERNEL); 69 i = change_page_attr(page, 1, PAGE_KERNEL);
69 global_flush_tlb(); 70 /* Caller's responsibility to call global_flush_tlb() for
71 * performance reasons */
70 return i; 72 return i;
71} 73}
72EXPORT_SYMBOL_GPL(unmap_page_from_agp); 74EXPORT_SYMBOL_GPL(unmap_page_from_agp);
@@ -153,6 +155,7 @@ void agp_free_memory(struct agp_memory *curr)
153 for (i = 0; i < curr->page_count; i++) { 155 for (i = 0; i < curr->page_count; i++) {
154 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); 156 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
155 } 157 }
158 global_flush_tlb();
156 } 159 }
157 agp_free_key(curr->key); 160 agp_free_key(curr->key);
158 vfree(curr->memory); 161 vfree(curr->memory);
@@ -210,7 +213,9 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
210 new->memory[i] = virt_to_gart(addr); 213 new->memory[i] = virt_to_gart(addr);
211 new->page_count++; 214 new->page_count++;
212 } 215 }
213 new->bridge = bridge; 216 global_flush_tlb();
217
218 new->bridge = bridge;
214 219
215 flush_agp_mappings(); 220 flush_agp_mappings();
216 221
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 58944cd271ea..be2e569ae910 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -514,9 +514,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
514{ 514{
515 void *page; 515 void *page;
516 516
517 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) 517 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
518 page = agp_generic_alloc_page(agp_bridge); 518 page = agp_generic_alloc_page(agp_bridge);
519 else 519 global_flush_tlb();
520 } else
520 /* Returning NULL would cause problems */ 521 /* Returning NULL would cause problems */
521 /* AK: really dubious code. */ 522 /* AK: really dubious code. */
522 page = (void *)~0UL; 523 page = (void *)~0UL;
@@ -525,8 +526,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
525 526
526static void i460_destroy_page (void *page) 527static void i460_destroy_page (void *page)
527{ 528{
528 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) 529 if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
529 agp_generic_destroy_page(page); 530 agp_generic_destroy_page(page);
531 global_flush_tlb();
532 }
530} 533}
531 534
532#endif /* I460_LARGE_IO_PAGES */ 535#endif /* I460_LARGE_IO_PAGES */
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index bf4cc9ffd5b1..027161ab88e9 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -270,6 +270,7 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
270 270
271 switch (pg_count) { 271 switch (pg_count) {
272 case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); 272 case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
273 global_flush_tlb();
273 break; 274 break;
274 case 4: 275 case 4:
275 /* kludge to get 4 physical pages for ARGB cursor */ 276 /* kludge to get 4 physical pages for ARGB cursor */
@@ -330,9 +331,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
330 if(curr->type == AGP_PHYS_MEMORY) { 331 if(curr->type == AGP_PHYS_MEMORY) {
331 if (curr->page_count == 4) 332 if (curr->page_count == 4)
332 i8xx_destroy_pages(gart_to_virt(curr->memory[0])); 333 i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
333 else 334 else {
334 agp_bridge->driver->agp_destroy_page( 335 agp_bridge->driver->agp_destroy_page(
335 gart_to_virt(curr->memory[0])); 336 gart_to_virt(curr->memory[0]));
337 global_flush_tlb();
338 }
336 vfree(curr->memory); 339 vfree(curr->memory);
337 } 340 }
338 kfree(curr); 341 kfree(curr);