X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fchar%2Fagp%2Fbackend.c;h=509adc403250a8126f72dac666493a680d06f8ad;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=33e1c707d7c59cbc6da08b3ebf8d759a1b544f09;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 33e1c707d..509adc403 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -1,5 +1,6 @@ /* * 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. @@ -18,12 +19,12 @@ * 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 @@ -42,34 +43,39 @@ * 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 +#define AGPGART_VERSION_MINOR 101 static 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); @@ -82,15 +88,16 @@ 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}, @@ -121,7 +128,6 @@ static int agp_find_max(void) (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; } @@ -135,16 +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(); + 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(); @@ -153,14 +160,14 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) 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"); @@ -168,7 +175,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) goto err_out; } got_keylist = 1; - + /* FIXME vmalloc'd memory not guaranteed contiguous */ memset(bridge->key_list, 0, PAGE_SIZE * 4); @@ -178,17 +185,16 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) 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; @@ -202,39 +208,48 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) 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); @@ -251,43 +266,38 @@ int agp_add_bridge(struct agp_bridge_data *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); @@ -295,11 +305,10 @@ 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); @@ -317,7 +326,7 @@ static int __init agp_init(void) return 0; } -void __exit agp_exit(void) +static void __exit agp_exit(void) { }