aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/generic.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2007-10-14 20:19:16 -0400
committerDave Airlie <airlied@optimus.(none)>2007-10-14 20:32:15 -0400
commita2721e998ede079db10f65e4b42310f79dc8f135 (patch)
tree32963c9bf40f3e0871d4d549bb6c3cf13abbb24c /drivers/char/agp/generic.c
parent23fd50450a34f2558070ceabb0bfebc1c9604af5 (diff)
AGP fix race condition between unmapping and freeing pages
With Andi's clflush fixup, we were getting hangs on server exit, flushing the mappings after freeing each page helped. This showed up a race condition where the pages after being freed could be reused before the agp mappings had been flushed. Flushing after each single page is a bad thing for future drm work, so make the page destroy a two pass unmapping all the pages, flushing the mappings, and then destroying the pages. Signed-off-by: Dave Airlie <airlied@linux.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'drivers/char/agp/generic.c')
-rw-r--r--drivers/char/agp/generic.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3db4f4076ed4..64b2f6d7059d 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
195 } 195 }
196 if (curr->page_count != 0) { 196 if (curr->page_count != 0) {
197 for (i = 0; i < curr->page_count; i++) { 197 for (i = 0; i < curr->page_count; i++) {
198 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); 198 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
199 } 199 }
200 flush_agp_mappings(); 200 flush_agp_mappings();
201 for (i = 0; i < curr->page_count; i++) {
202 curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
203 }
201 } 204 }
202 agp_free_key(curr->key); 205 agp_free_key(curr->key);
203 agp_free_page_array(curr); 206 agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
1176EXPORT_SYMBOL(agp_generic_alloc_page); 1179EXPORT_SYMBOL(agp_generic_alloc_page);
1177 1180
1178 1181
1179void agp_generic_destroy_page(void *addr) 1182void agp_generic_destroy_page(void *addr, int flags)
1180{ 1183{
1181 struct page *page; 1184 struct page *page;
1182 1185
@@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr)
1184 return; 1187 return;
1185 1188
1186 page = virt_to_page(addr); 1189 page = virt_to_page(addr);
1187 unmap_page_from_agp(page); 1190 if (flags & AGP_PAGE_DESTROY_UNMAP)
1188 put_page(page); 1191 unmap_page_from_agp(page);
1189 free_page((unsigned long)addr); 1192
1190 atomic_dec(&agp_bridge->current_memory_agp); 1193 if (flags & AGP_PAGE_DESTROY_FREE) {
1194 put_page(page);
1195 free_page((unsigned long)addr);
1196 atomic_dec(&agp_bridge->current_memory_agp);
1197 }
1191} 1198}
1192EXPORT_SYMBOL(agp_generic_destroy_page); 1199EXPORT_SYMBOL(agp_generic_destroy_page);
1193 1200