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

Commit 3d06f7a5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'agp-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/agp-2.6

* 'agp-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied/agp-2.6:
  fix use after free in amd create gatt pages
  AGP fix race condition between unmapping and freeing pages
parents 13626cb9 bdc3e603
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -58,6 +58,9 @@ struct gatt_mask {
	 * devices this will probably be ignored */
};

#define AGP_PAGE_DESTROY_UNMAP 1
#define AGP_PAGE_DESTROY_FREE 2

struct aper_size_info_8 {
	int size;
	int num_entries;
@@ -113,7 +116,7 @@ struct agp_bridge_driver {
	struct agp_memory *(*alloc_by_type) (size_t, int);
	void (*free_by_type)(struct agp_memory *);
	void *(*agp_alloc_page)(struct agp_bridge_data *);
	void (*agp_destroy_page)(void *);
	void (*agp_destroy_page)(void *, int flags);
        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
};

@@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
void agp_generic_free_by_type(struct agp_memory *curr);
void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
void agp_generic_destroy_page(void *addr);
void agp_generic_destroy_page(void *addr, int flags);
void agp_free_key(int key);
int agp_num_entries(void);
u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
+16 −11
Original line number Diff line number Diff line
@@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
	return addr;
}

static void ali_destroy_page(void * addr)
static void ali_destroy_page(void * addr, int flags)
{
	if (addr) {
		if (flags & AGP_PAGE_DESTROY_UNMAP) {
			global_cache_flush();	/* is this really needed?  --hch */
		agp_generic_destroy_page(addr);
			agp_generic_destroy_page(addr, flags);
			global_flush_tlb();
		} else
			agp_generic_destroy_page(addr, flags);
	}
}

static void m1541_destroy_page(void * addr)
static void m1541_destroy_page(void * addr, int flags)
{
	u32 temp;

	if (addr == NULL)
		return;

	if (flags & AGP_PAGE_DESTROY_UNMAP) {
		global_cache_flush();

		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
				       (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
					 virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
	agp_generic_destroy_page(addr);
	}
	agp_generic_destroy_page(addr, flags);
}


+2 −7
Original line number Diff line number Diff line
@@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables)

	for (i = 0; i < nr_tables; i++) {
		entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
		tables[i] = entry;
		if (entry == NULL) {
			while (i > 0) {
				kfree(tables[i-1]);
				i--;
			}
			kfree(tables);
			retval = -ENOMEM;
			break;
		}
		tables[i] = entry;
		retval = amd_create_page_map(entry);
		if (retval != 0)
			break;
	}
	amd_irongate_private.num_tables = nr_tables;
	amd_irongate_private.num_tables = i;
	amd_irongate_private.gatt_pages = tables;

	if (retval != 0)
+8 −4
Original line number Diff line number Diff line
@@ -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);
	}
}

+13 −6
Original line number Diff line number Diff line
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
	}
	if (curr->page_count != 0) {
		for (i = 0; i < curr->page_count; i++) {
			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
		}
		flush_agp_mappings();
		for (i = 0; i < curr->page_count; i++) {
			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
		}
	}
	agp_free_key(curr->key);
	agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
EXPORT_SYMBOL(agp_generic_alloc_page);


void agp_generic_destroy_page(void *addr)
void agp_generic_destroy_page(void *addr, int flags)
{
	struct page *page;

@@ -1184,11 +1187,15 @@ void agp_generic_destroy_page(void *addr)
		return;

	page = virt_to_page(addr);
	if (flags & AGP_PAGE_DESTROY_UNMAP)
		unmap_page_from_agp(page);

	if (flags & AGP_PAGE_DESTROY_FREE) {
		put_page(page);
		free_page((unsigned long)addr);
		atomic_dec(&agp_bridge->current_memory_agp);
	}
}
EXPORT_SYMBOL(agp_generic_destroy_page);

/* End Basic Page Allocation Routines */
Loading