diff options
author | Dave Airlie <airlied@redhat.com> | 2007-10-15 10:19:16 +1000 |
---|---|---|
committer | Dave Airlie <airlied@optimus.(none)> | 2007-10-15 10:32:15 +1000 |
commit | a2721e998ede079db10f65e4b42310f79dc8f135 (patch) | |
tree | 32963c9bf40f3e0871d4d549bb6c3cf13abbb24c /drivers/char/agp/backend.c | |
parent | 23fd50450a34f2558070ceabb0bfebc1c9604af5 (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/backend.c')
-rw-r--r-- | drivers/char/agp/backend.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 1b47c89a1b99..832ded20fe70 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) err_out: if (bridge->driver->needs_scratch_page) { - bridge->driver->agp_destroy_page( - gart_to_virt(bridge->scratch_page_real)); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_UNMAP); flush_agp_mappings(); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_FREE); } if (got_gatt) bridge->driver->free_gatt_table(bridge); @@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) if (bridge->driver->agp_destroy_page && bridge->driver->needs_scratch_page) { - bridge->driver->agp_destroy_page( - gart_to_virt(bridge->scratch_page_real)); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_UNMAP); flush_agp_mappings(); + bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), + AGP_PAGE_DESTROY_FREE); } } |