/*
* AGPGART driver.
* Copyright (C) 2004 Silicon Graphics, Inc.
* Copyright (C) 2002-2005 Dave Jones.
* Copyright (C) 1999 Jeff Hartmann.
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
#include <linux/agp_backend.h>
#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include "agp.h"
__u32 *agp_gatt_table;
int agp_memory_reserved;
/*
* Needed by the Nforce GART driver for the time being. Would be
* nice to do this some other way instead of needing this export.
*/
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 -
* They use the basic page allocation routines to do the brunt of the work.
*/
void agp_free_key(int key)
{
if (key < 0)
return;
if (key < MAXKEY)
clear_bit(key, agp_bridge->key_list);
}
EXPORT_SYMBOL(agp_free_key);
static int agp_get_key(void)
{
int bit;
bit = find_first_zero_bit(agp_bridge->key_list, MAXKEY);
if (bit < MAXKEY) {
set_bit(bit, agp_bridge->key_list);
return bit;
}
return -1;
}
struct agp_memory *agp_create_memory(int scratch_pages)
{
struct agp_memory *new;
new = kmalloc(sizeof(struct agp_memory), GFP_KERNEL);
if (new == NULL)
return NULL;
memset(new, 0, sizeof(struct agp_memory));
new->key = agp_get_key();
if (new->key < 0) {
kfree(new);
return NULL;
}
new->memory = vmalloc(PAGE_SIZE * scratch_pages);
if (new->memory == NULL) {
agp_free_key(new->key);
kfree(new);
return NULL;
}
new->num_scratch_pages = scratch_pages;
return new;
}
EXPORT_SYMBOL(agp_create_memory);
/**
* agp_free_memory - free memory associated with an agp_memory pointer.
*
* @curr: agp_memory pointer to be freed.
*
* It is the only function that can be called when the backend is not owned
* by the caller. (So it can free memory on client death.)
*/
void