Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcea424d authored by Arjan van dev Ven's avatar Arjan van dev Ven Committed by Dave Airlie
Browse files

fix historic ioremap() abuse in AGP



Several AGP drivers right now use ioremap_nocache() on kernel ram in order
to turn a page of regular memory uncached.

There are two problems with this:

    1) This is a total nightmare for the ioremap() implementation to keep
       various mappings of the same page coherent.

    2) It's a total nightmare for the AGP code since it adds a ton of
       complexity in terms of keeping track of 2 different pointers to
       the same thing, in terms of error handling etc etc.

This patch fixes this by making the AGP drivers use the new
set_memory_XX APIs instead.

Note: amd-k7-agp.c is built on Alpha too, and generic.c is built
on ia64 as well, which do not yet have the set_memory_*() APIs,
so for them some we have a few ugly #ifdefs - hopefully they'll
be fixed soon.

Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 16469a0e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -126,6 +126,8 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
			return NULL;
	}

	WARN_ON_ONCE(page_is_ram(pfn));

	switch (mode) {
	case IOR_MODE_UNCACHED:
	default:
+9 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
	if (page_map->real == NULL)
		return -ENOMEM;

#ifndef CONFIG_X86
	SetPageReserved(virt_to_page(page_map->real));
	global_cache_flush();
	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
@@ -52,6 +53,10 @@ static int amd_create_page_map(struct amd_page_map *page_map)
		return -ENOMEM;
	}
	global_cache_flush();
#else
	set_memory_uc(page_map->real, 1);
	page_map->remapped = page_map->real;
#endif

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
		writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -63,8 +68,12 @@ static int amd_create_page_map(struct amd_page_map *page_map)

static void amd_free_page_map(struct amd_page_map *page_map)
{
#ifndef CONFIG_X86
	iounmap(page_map->remapped);
	ClearPageReserved(virt_to_page(page_map->real));
#else
	set_memory_wb(page_map->real, 1);
#endif
	free_page((unsigned long) page_map->real);
}

+3 −13
Original line number Diff line number Diff line
@@ -60,18 +60,9 @@ static int ati_create_page_map(struct ati_page_map *page_map)
	if (page_map->real == NULL)
		return -ENOMEM;

	SetPageReserved(virt_to_page(page_map->real));
	set_memory_uc(page_map->real, 1);
	err = map_page_into_agp(virt_to_page(page_map->real));
	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
					    PAGE_SIZE);
	if (page_map->remapped == NULL || err) {
		ClearPageReserved(virt_to_page(page_map->real));
		free_page((unsigned long) page_map->real);
		page_map->real = NULL;
		return -ENOMEM;
	}
	/*CACHE_FLUSH();*/
	global_cache_flush();
	page_map->remapped = page_map->real;

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
		writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -85,8 +76,7 @@ static int ati_create_page_map(struct ati_page_map *page_map)
static void ati_free_page_map(struct ati_page_map *page_map)
{
	unmap_page_from_agp(virt_to_page(page_map->real));
	iounmap(page_map->remapped);
	ClearPageReserved(virt_to_page(page_map->real));
	set_memory_wb(page_map->real, 1);
	free_page((unsigned long) page_map->real);
}

+9 −0
Original line number Diff line number Diff line
@@ -932,9 +932,14 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
	agp_gatt_table = (void *)table;

	bridge->driver->cache_flush();
#ifdef CONFIG_X86
	set_memory_uc((unsigned long)table, 1 << page_order);
	bridge->gatt_table = (void *)table;
#else
	bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
					(PAGE_SIZE * (1 << page_order)));
	bridge->driver->cache_flush();
#endif

	if (bridge->gatt_table == NULL) {
		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
@@ -991,7 +996,11 @@ int agp_generic_free_gatt_table(struct agp_bridge_data *bridge)
	 * called, then all agp memory is deallocated and removed
	 * from the table. */

#ifdef CONFIG_X86
	set_memory_wb((unsigned long)bridge->gatt_table, 1 << page_order);
#else
	iounmap(bridge->gatt_table);
#endif
	table = (char *) bridge->gatt_table_real;
	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);

+5 −13
Original line number Diff line number Diff line
@@ -52,28 +52,20 @@ static int serverworks_create_page_map(struct serverworks_page_map *page_map)
	if (page_map->real == NULL) {
		return -ENOMEM;
	}
	SetPageReserved(virt_to_page(page_map->real));
	global_cache_flush();
	page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
					    PAGE_SIZE);
	if (page_map->remapped == NULL) {
		ClearPageReserved(virt_to_page(page_map->real));
		free_page((unsigned long) page_map->real);
		page_map->real = NULL;
		return -ENOMEM;
	}
	global_cache_flush();

	set_memory_uc(page_map->real, 1);
	page_map->remapped = page_map->real;

	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++)
		writel(agp_bridge->scratch_page, page_map->remapped+i);
		/* Red Pen: Everyone else does pci posting flush here */

	return 0;
}

static void serverworks_free_page_map(struct serverworks_page_map *page_map)
{
	iounmap(page_map->remapped);
	ClearPageReserved(virt_to_page(page_map->real));
	set_memory_wb(page_map->real, 1);
	free_page((unsigned long) page_map->real);
}