Skip to content

Commit

Permalink
agp: switch AGP to use page array instead of unsigned long array
Browse files Browse the repository at this point in the history
This switches AGP to use an array of pages for tracking the
pages allocated to the GART. This should enable GEM on PAE to work
a lot better as we can pass highmem pages to the PAT code and it will
do the right thing with them.

Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Dave Airlie committed Jun 19, 2009
1 parent 2908826 commit 07613ba
Show file tree
Hide file tree
Showing 21 changed files with 152 additions and 146 deletions.
12 changes: 6 additions & 6 deletions drivers/char/agp/agp.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@ struct agp_bridge_driver {
void (*agp_enable)(struct agp_bridge_data *, u32);
void (*cleanup)(void);
void (*tlb_flush)(struct agp_memory *);
unsigned long (*mask_memory)(struct agp_bridge_data *, unsigned long, int);
unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int);
void (*cache_flush)(void);
int (*create_gatt_table)(struct agp_bridge_data *);
int (*free_gatt_table)(struct agp_bridge_data *);
int (*insert_memory)(struct agp_memory *, off_t, int);
int (*remove_memory)(struct agp_memory *, off_t, int);
struct agp_memory *(*alloc_by_type) (size_t, int);
void (*free_by_type)(struct agp_memory *);
void *(*agp_alloc_page)(struct agp_bridge_data *);
struct page *(*agp_alloc_page)(struct agp_bridge_data *);
int (*agp_alloc_pages)(struct agp_bridge_data *, struct agp_memory *, size_t);
void (*agp_destroy_page)(void *, int flags);
void (*agp_destroy_page)(struct page *, int flags);
void (*agp_destroy_pages)(struct agp_memory *);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
void (*chipset_flush)(struct agp_bridge_data *);
Expand Down Expand Up @@ -278,10 +278,10 @@ int agp_generic_insert_memory(struct agp_memory *mem, off_t pg_start, int type);
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);
struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge);
int agp_generic_alloc_pages(struct agp_bridge_data *agp_bridge,
struct agp_memory *memory, size_t page_count);
void agp_generic_destroy_page(void *addr, int flags);
void agp_generic_destroy_page(struct page *page, int flags);
void agp_generic_destroy_pages(struct agp_memory *memory);
void agp_free_key(int key);
int agp_num_entries(void);
Expand All @@ -291,7 +291,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge);
void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
unsigned long addr, int type);
struct page *page, int type);
int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
int type);
struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
Expand Down
26 changes: 13 additions & 13 deletions drivers/char/agp/ali-agp.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,37 +141,37 @@ static void m1541_cache_flush(void)
}
}

static void *m1541_alloc_page(struct agp_bridge_data *bridge)
static struct page *m1541_alloc_page(struct agp_bridge_data *bridge)
{
void *addr = agp_generic_alloc_page(agp_bridge);
struct page *page = agp_generic_alloc_page(agp_bridge);
u32 temp;

if (!addr)
if (!page)
return NULL;

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 ));
return addr;
phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN ));
return page;
}

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

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

if (addr == NULL)
if (page == NULL)
return;

if (flags & AGP_PAGE_DESTROY_UNMAP) {
Expand All @@ -180,9 +180,9 @@ static void m1541_destroy_page(void * addr, int flags)
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));
phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN));
}
agp_generic_destroy_page(addr, flags);
agp_generic_destroy_page(page, flags);
}


Expand Down
2 changes: 1 addition & 1 deletion drivers/char/agp/amd-k7-agp.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_generic_mask_memory(agp_bridge,
mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
}
amd_irongate_tlbflush(mem);
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/agp/amd64-agp.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)

for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
tmp = agp_bridge->driver->mask_memory(agp_bridge,
mem->memory[i], mask_type);
mem->pages[i], mask_type);

BUG_ON(tmp & 0xffffff0000000ffcULL);
pte = (tmp & 0x000000ff00000000ULL) >> 28;
Expand Down
5 changes: 3 additions & 2 deletions drivers/char/agp/ati-agp.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,9 @@ static int ati_insert_memory(struct agp_memory * mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_bridge->driver->mask_memory(agp_bridge,
mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
writel(agp_bridge->driver->mask_memory(agp_bridge,
mem->pages[i], mem->type),
cur_gatt+GET_GATT_OFF(addr));
readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
}
agp_bridge->driver->tlb_flush(mem);
Expand Down
8 changes: 4 additions & 4 deletions drivers/char/agp/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,17 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
bridge->version = &agp_current_version;

if (bridge->driver->needs_scratch_page) {
void *addr = bridge->driver->agp_alloc_page(bridge);
struct page *page = bridge->driver->agp_alloc_page(bridge);

if (!addr) {
if (!page) {
dev_err(&bridge->dev->dev,
"can't get memory for scratch page\n");
return -ENOMEM;
}

bridge->scratch_page_real = virt_to_gart(addr);
bridge->scratch_page_real = phys_to_gart(page_to_phys(page));
bridge->scratch_page =
bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0);
bridge->driver->mask_memory(bridge, page, 0);
}

size_value = bridge->driver->fetch_size();
Expand Down
5 changes: 3 additions & 2 deletions drivers/char/agp/efficeon-agp.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ static const struct gatt_mask efficeon_generic_masks[] =
};

/* This function does the same thing as mask_memory() for this chipset... */
static inline unsigned long efficeon_mask_memory(unsigned long addr)
static inline unsigned long efficeon_mask_memory(struct page *page)
{
unsigned long addr = phys_to_gart(page_to_phys(page));
return addr | 0x00000001;
}

Expand Down Expand Up @@ -257,7 +258,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t
last_page = NULL;
for (i = 0; i < count; i++) {
int index = pg_start + i;
unsigned long insert = efficeon_mask_memory(mem->memory[i]);
unsigned long insert = efficeon_mask_memory(mem->pages[i]);

page = (unsigned int *) efficeon_private.l1_table[index >> 10];

Expand Down
69 changes: 28 additions & 41 deletions drivers/char/agp/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ EXPORT_SYMBOL(agp_flush_chipset);

void agp_alloc_page_array(size_t size, struct agp_memory *mem)
{
mem->memory = NULL;
mem->pages = NULL;
mem->vmalloc_flag = false;

if (size <= 2*PAGE_SIZE)
mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
if (mem->memory == NULL) {
mem->memory = vmalloc(size);
mem->pages = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
if (mem->pages == NULL) {
mem->pages = vmalloc(size);
mem->vmalloc_flag = true;
}
}
Expand All @@ -110,9 +110,9 @@ EXPORT_SYMBOL(agp_alloc_page_array);
void agp_free_page_array(struct agp_memory *mem)
{
if (mem->vmalloc_flag) {
vfree(mem->memory);
vfree(mem->pages);
} else {
kfree(mem->memory);
kfree(mem->pages);
}
}
EXPORT_SYMBOL(agp_free_page_array);
Expand All @@ -136,7 +136,7 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)

agp_alloc_page_array(alloc_size, new);

if (new->memory == NULL) {
if (new->pages == NULL) {
agp_free_key(new->key);
kfree(new);
return NULL;
Expand All @@ -162,7 +162,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)

agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);

if (new->memory == NULL) {
if (new->pages == NULL) {
agp_free_key(new->key);
kfree(new);
return NULL;
Expand Down Expand Up @@ -206,15 +206,13 @@ void agp_free_memory(struct agp_memory *curr)
} else {

for (i = 0; i < curr->page_count; i++) {
curr->memory[i] = (unsigned long)gart_to_virt(
curr->memory[i]);
curr->bridge->driver->agp_destroy_page(
(void *)curr->memory[i],
curr->pages[i],
AGP_PAGE_DESTROY_UNMAP);
}
for (i = 0; i < curr->page_count; i++) {
curr->bridge->driver->agp_destroy_page(
(void *)curr->memory[i],
curr->pages[i],
AGP_PAGE_DESTROY_FREE);
}
}
Expand Down Expand Up @@ -282,13 +280,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
}

for (i = 0; i < page_count; i++) {
void *addr = bridge->driver->agp_alloc_page(bridge);
struct page *page = bridge->driver->agp_alloc_page(bridge);

if (addr == NULL) {
if (page == NULL) {
agp_free_memory(new);
return NULL;
}
new->memory[i] = virt_to_gart(addr);
new->pages[i] = page;
new->page_count++;
}
new->bridge = bridge;
Expand Down Expand Up @@ -1134,7 +1132,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
}

for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type),
bridge->gatt_table+j);
}
readl(bridge->gatt_table+j-1); /* PCI Posting. */
Expand Down Expand Up @@ -1204,7 +1202,7 @@ struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
return NULL;

for (i = 0; i < page_count; i++)
new->memory[i] = 0;
new->pages[i] = 0;
new->page_count = 0;
new->type = type;
new->num_scratch_pages = pages;
Expand Down Expand Up @@ -1237,23 +1235,20 @@ int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *m
get_page(page);
atomic_inc(&agp_bridge->current_memory_agp);

/* set_memory_array_uc() needs virtual address */
mem->memory[i] = (unsigned long)page_address(page);
mem->pages[i] = page;
mem->page_count++;
}

#ifdef CONFIG_X86
set_memory_array_uc(mem->memory, num_pages);
set_pages_array_uc(mem->pages, num_pages);
#endif
ret = 0;
out:
for (i = 0; i < mem->page_count; i++)
mem->memory[i] = virt_to_gart((void *)mem->memory[i]);
return ret;
}
EXPORT_SYMBOL(agp_generic_alloc_pages);

void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge)
{
struct page * page;

Expand All @@ -1265,56 +1260,47 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)

get_page(page);
atomic_inc(&agp_bridge->current_memory_agp);
return page_address(page);
return page;
}
EXPORT_SYMBOL(agp_generic_alloc_page);

void agp_generic_destroy_pages(struct agp_memory *mem)
{
int i;
void *addr;
struct page *page;

if (!mem)
return;

for (i = 0; i < mem->page_count; i++)
mem->memory[i] = (unsigned long)gart_to_virt(mem->memory[i]);

#ifdef CONFIG_X86
set_memory_array_wb(mem->memory, mem->page_count);
set_pages_array_wb(mem->pages, mem->page_count);
#endif

for (i = 0; i < mem->page_count; i++) {
addr = (void *)mem->memory[i];
page = virt_to_page(addr);
page = mem->pages[i];

#ifndef CONFIG_X86
unmap_page_from_agp(page);
#endif

put_page(page);
free_page((unsigned long)addr);
__free_page(page);
atomic_dec(&agp_bridge->current_memory_agp);
mem->memory[i] = 0;
mem->pages[i] = NULL;
}
}
EXPORT_SYMBOL(agp_generic_destroy_pages);

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

if (addr == NULL)
if (page == NULL)
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);
__free_page(page);
atomic_dec(&agp_bridge->current_memory_agp);
}
}
Expand Down Expand Up @@ -1361,8 +1347,9 @@ void global_cache_flush(void)
EXPORT_SYMBOL(global_cache_flush);

unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
unsigned long addr, int type)
struct page *page, int type)
{
unsigned long addr = phys_to_gart(page_to_phys(page));
/* memory type is ignored in the generic routine */
if (bridge->driver->masks)
return addr | bridge->driver->masks[0].mask;
Expand Down
Loading

0 comments on commit 07613ba

Please sign in to comment.