Commit 30009319 authored by Dave Jones's avatar Dave Jones

[AGPGART] Fix TLB flushing issues with change_page_attr()

Calls to change_page_attr() need an explicit call to
global_flush_tlb() afterwards.  The AGP code didn't
do this in a number of cases.  This patch makes
map_page_into_agp/unmap_page_from_agp do the calls
themselves, which takes care of most of the problem.

The Intel AGP driver also has some slightly different calls to what
map_page_into_agp() does, as it changes 4 contiguous pages.
Introduce explicit flushes afterwards there too.

Thanks to Alan Cox for pointing this out.
Signed-off-by: default avatarDave Jones <davej@redhat.com>
parent 54fced54
...@@ -61,9 +61,6 @@ static int ati_create_page_map(ati_page_map *page_map) ...@@ -61,9 +61,6 @@ static int ati_create_page_map(ati_page_map *page_map)
SetPageReserved(virt_to_page(page_map->real)); SetPageReserved(virt_to_page(page_map->real));
err = map_page_into_agp(virt_to_page(page_map->real)); err = map_page_into_agp(virt_to_page(page_map->real));
/* CACHE_FLUSH(); */
global_cache_flush();
page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
PAGE_SIZE); PAGE_SIZE);
if (page_map->remapped == NULL || err) { if (page_map->remapped == NULL || err) {
......
...@@ -35,7 +35,10 @@ ...@@ -35,7 +35,10 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include "agp.h" #include "agp.h"
__u32 *agp_gatt_table; __u32 *agp_gatt_table;
...@@ -47,6 +50,26 @@ int agp_memory_reserved; ...@@ -47,6 +50,26 @@ int agp_memory_reserved;
*/ */
EXPORT_SYMBOL_GPL(agp_memory_reserved); EXPORT_SYMBOL_GPL(agp_memory_reserved);
#if defined(CONFIG_X86)
int map_page_into_agp(struct page *page)
{
int i;
i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
global_flush_tlb();
return i;
}
EXPORT_SYMBOL_GPL(map_page_into_agp);
int unmap_page_from_agp(struct page *page)
{
int i;
i = change_page_attr(page, 1, PAGE_KERNEL);
global_flush_tlb();
return i;
}
EXPORT_SYMBOL_GPL(unmap_page_from_agp);
#endif
/* /*
* Generic routines for handling agp_memory structures - * Generic routines for handling agp_memory structures -
* They use the basic page allocation routines to do the brunt of the work. * They use the basic page allocation routines to do the brunt of the work.
......
...@@ -161,13 +161,15 @@ static void *i8xx_alloc_pages(void) ...@@ -161,13 +161,15 @@ static void *i8xx_alloc_pages(void)
struct page * page; struct page * page;
page = alloc_pages(GFP_KERNEL, 2); page = alloc_pages(GFP_KERNEL, 2);
if (page == NULL) { if (page == NULL)
return NULL; return NULL;
}
if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
global_flush_tlb();
__free_page(page); __free_page(page);
return NULL; return NULL;
} }
global_flush_tlb();
get_page(page); get_page(page);
SetPageLocked(page); SetPageLocked(page);
atomic_inc(&agp_bridge->current_memory_agp); atomic_inc(&agp_bridge->current_memory_agp);
...@@ -183,6 +185,7 @@ static void i8xx_destroy_pages(void *addr) ...@@ -183,6 +185,7 @@ static void i8xx_destroy_pages(void *addr)
page = virt_to_page(addr); page = virt_to_page(addr);
change_page_attr(page, 4, PAGE_KERNEL); change_page_attr(page, 4, PAGE_KERNEL);
global_flush_tlb();
put_page(page); put_page(page);
unlock_page(page); unlock_page(page);
free_pages((unsigned long)addr, 2); free_pages((unsigned long)addr, 2);
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
* data corruption on some CPUs. * data corruption on some CPUs.
*/ */
#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) int map_page_into_agp(struct page *page);
#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL) int unmap_page_from_agp(struct page *page);
#define flush_agp_mappings() global_flush_tlb() #define flush_agp_mappings() global_flush_tlb()
/* Could use CLFLUSH here if the cpu supports it. But then it would /* Could use CLFLUSH here if the cpu supports it. But then it would
......
...@@ -10,9 +10,8 @@ ...@@ -10,9 +10,8 @@
* with different cachability attributes for the same page. * with different cachability attributes for the same page.
*/ */
#define map_page_into_agp(page) \ int map_page_into_agp(struct page *page);
change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) int unmap_page_from_agp(struct page *page);
#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
#define flush_agp_mappings() global_flush_tlb() #define flush_agp_mappings() global_flush_tlb()
/* Could use CLFLUSH here if the cpu supports it. But then it would /* Could use CLFLUSH here if the cpu supports it. But then it would
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment