/*
* AGPGART driver backend routines.
+ * Copyright (C) 2004 Silicon Graphics, Inc.
* Copyright (C) 2002-2003 Dave Jones.
* Copyright (C) 1999 Jeff Hartmann.
* Copyright (C) 1999 Precision Insight, Inc.
* 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, DAVE JONES, 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
+ * JEFF HARTMANN, DAVE JONES, 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:
+ * TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
#include <linux/module.h>
* fix some real stupidity. It's only by chance we can bump
* past 0.99 at all due to some boolean logic error. */
#define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 100
-static struct agp_version agp_current_version =
+#define AGPGART_VERSION_MINOR 101
+static const struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
.minor = AGPGART_VERSION_MINOR,
};
-static int agp_count=0;
+struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
+ &agp_generic_find_bridge;
-struct agp_bridge_data agp_bridge_dummy = { .type = NOT_SUPPORTED };
-struct agp_bridge_data *agp_bridge = &agp_bridge_dummy;
+struct agp_bridge_data *agp_bridge;
+LIST_HEAD(agp_bridges);
EXPORT_SYMBOL(agp_bridge);
-
+EXPORT_SYMBOL(agp_bridges);
+EXPORT_SYMBOL(agp_find_bridge);
/**
- * agp_backend_acquire - attempt to acquire the agp backend.
+ * agp_backend_acquire - attempt to acquire an agp backend.
*
- * returns -EBUSY if agp is in use,
- * returns 0 if the caller owns the agp backend
*/
-int agp_backend_acquire(void)
+struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
{
- if (agp_bridge->type == NOT_SUPPORTED)
- return -EINVAL;
- if (atomic_read(&agp_bridge->agp_in_use))
- return -EBUSY;
- atomic_inc(&agp_bridge->agp_in_use);
- return 0;
+ struct agp_bridge_data *bridge;
+
+ bridge = agp_find_bridge(pdev);
+
+ if (!bridge)
+ return NULL;
+
+ if (atomic_read(&bridge->agp_in_use))
+ return NULL;
+ atomic_inc(&bridge->agp_in_use);
+ return bridge;
}
EXPORT_SYMBOL(agp_backend_acquire);
*
* (Ensure that all memory it bound is unbound.)
*/
-void agp_backend_release(void)
+void agp_backend_release(struct agp_bridge_data *bridge)
{
- if (agp_bridge->type != NOT_SUPPORTED)
- atomic_dec(&agp_bridge->agp_in_use);
+
+ if (bridge)
+ atomic_dec(&bridge->agp_in_use);
}
EXPORT_SYMBOL(agp_backend_release);
-struct { int mem, agp; } maxes_table[] = {
+static const struct { int mem, agp; } maxes_table[] = {
{0, 0},
{32, 4},
{64, 28},
(maxes_table[index].agp - maxes_table[index - 1].agp)) /
(maxes_table[index].mem - maxes_table[index - 1].mem);
- printk(KERN_INFO PFX "Maximum main memory to use for agp memory: %ldM\n", result);
result = result << (20 - PAGE_SHIFT);
return result;
}
bridge->version = &agp_current_version;
if (bridge->driver->needs_scratch_page) {
- void *addr = bridge->driver->agp_alloc_page();
+ void *addr = bridge->driver->agp_alloc_page(bridge);
if (!addr) {
printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
return -ENOMEM;
}
+ flush_agp_mappings();
- bridge->scratch_page_real = virt_to_phys(addr);
+ bridge->scratch_page_real = virt_to_gart(addr);
bridge->scratch_page =
- bridge->driver->mask_memory(bridge->scratch_page_real, 0);
+ bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0);
}
size_value = bridge->driver->fetch_size();
rc = -EINVAL;
goto err_out;
}
- if (bridge->driver->create_gatt_table()) {
+ if (bridge->driver->create_gatt_table(bridge)) {
printk(KERN_ERR PFX
"unable to get memory for graphics translation table.\n");
rc = -ENOMEM;
goto err_out;
}
got_gatt = 1;
-
+
bridge->key_list = vmalloc(PAGE_SIZE * 4);
if (bridge->key_list == NULL) {
printk(KERN_ERR PFX "error allocating memory for key lists.\n");
goto err_out;
}
got_keylist = 1;
-
+
/* FIXME vmalloc'd memory not guaranteed contiguous */
memset(bridge->key_list, 0, PAGE_SIZE * 4);
goto err_out;
}
- printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
- size_value, bridge->gart_bus_addr);
-
return 0;
err_out:
- if (bridge->driver->needs_scratch_page)
+ if (bridge->driver->needs_scratch_page) {
bridge->driver->agp_destroy_page(
- phys_to_virt(bridge->scratch_page_real));
+ gart_to_virt(bridge->scratch_page_real));
+ flush_agp_mappings();
+ }
if (got_gatt)
- bridge->driver->free_gatt_table();
+ bridge->driver->free_gatt_table(bridge);
if (got_keylist) {
vfree(bridge->key_list);
bridge->key_list = NULL;
if (bridge->driver->cleanup)
bridge->driver->cleanup();
if (bridge->driver->free_gatt_table)
- bridge->driver->free_gatt_table();
- if (bridge->key_list) {
- vfree(bridge->key_list);
- bridge->key_list = NULL;
- }
+ bridge->driver->free_gatt_table(bridge);
+
+ vfree(bridge->key_list);
+ bridge->key_list = NULL;
if (bridge->driver->agp_destroy_page &&
- bridge->driver->needs_scratch_page)
+ bridge->driver->needs_scratch_page) {
bridge->driver->agp_destroy_page(
- phys_to_virt(bridge->scratch_page_real));
+ gart_to_virt(bridge->scratch_page_real));
+ flush_agp_mappings();
+ }
}
-static const drm_agp_t drm_agp = {
- &agp_free_memory,
- &agp_allocate_memory,
- &agp_bind_memory,
- &agp_unbind_memory,
- &agp_enable,
- &agp_backend_acquire,
- &agp_backend_release,
- &agp_copy_info
-};
+/* When we remove the global variable agp_bridge from all drivers
+ * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
+ */
-/* XXX Kludge alert: agpgart isn't ready for multiple bridges yet */
struct agp_bridge_data *agp_alloc_bridge(void)
{
- return agp_bridge;
+ struct agp_bridge_data *bridge;
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return NULL;
+
+ atomic_set(&bridge->agp_in_use, 0);
+ atomic_set(&bridge->current_memory_agp, 0);
+
+ if (list_empty(&agp_bridges))
+ agp_bridge = bridge;
+
+ return bridge;
}
EXPORT_SYMBOL(agp_alloc_bridge);
void agp_put_bridge(struct agp_bridge_data *bridge)
{
+ kfree(bridge);
+
+ if (list_empty(&agp_bridges))
+ agp_bridge = NULL;
}
EXPORT_SYMBOL(agp_put_bridge);
return -EINVAL;
}
- if (agp_count) {
- printk (KERN_INFO PFX
- "Only one agpgart device currently supported.\n");
- return -ENODEV;
- }
-
/* Grab reference on the chipset driver. */
if (!try_module_get(bridge->driver->owner)) {
printk (KERN_INFO PFX "Couldn't lock chipset driver.\n");
return -EINVAL;
}
- bridge->type = SUPPORTED;
-
- error = agp_backend_initialize(agp_bridge);
+ error = agp_backend_initialize(bridge);
if (error) {
printk (KERN_INFO PFX "agp_backend_initialize() failed.\n");
goto err_out;
}
- error = agp_frontend_initialize();
- if (error) {
- printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n");
- goto frontend_err;
- }
+ if (list_empty(&agp_bridges)) {
+ error = agp_frontend_initialize();
+ if (error) {
+ printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n");
+ goto frontend_err;
+ }
+
+ printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
+ bridge->driver->fetch_size(), bridge->gart_bus_addr);
- /* FIXME: What to do with this? */
- inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
+ }
- agp_count++;
+ list_add(&bridge->list, &agp_bridges);
return 0;
frontend_err:
- agp_backend_cleanup(agp_bridge);
+ agp_backend_cleanup(bridge);
err_out:
- bridge->type = NOT_SUPPORTED;
module_put(bridge->driver->owner);
+ agp_put_bridge(bridge);
return error;
}
EXPORT_SYMBOL_GPL(agp_add_bridge);
void agp_remove_bridge(struct agp_bridge_data *bridge)
{
- bridge->type = NOT_SUPPORTED;
- agp_frontend_cleanup();
agp_backend_cleanup(bridge);
- inter_module_unregister("drm_agp");
- agp_count--;
+ list_del(&bridge->list);
+ if (list_empty(&agp_bridges))
+ agp_frontend_cleanup();
module_put(bridge->driver->owner);
}
EXPORT_SYMBOL_GPL(agp_remove_bridge);
return 0;
}
-void __exit agp_exit(void)
+static void __exit agp_exit(void)
{
}