vserver 2.0 rc7
[linux-2.6.git] / drivers / char / agp / backend.c
index 9eeaeea..4d4e602 100644 (file)
@@ -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.
  * 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
+#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 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,16 @@ 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;
                }
 
-               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 +159,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 +174,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 +184,14 @@ 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)
                bridge->driver->agp_destroy_page(
-                               phys_to_virt(bridge->scratch_page_real));
+                               gart_to_virt(bridge->scratch_page_real));
        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,7 +205,7 @@ 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();
+               bridge->driver->free_gatt_table(bridge);
        if (bridge->key_list) {
                vfree(bridge->key_list);
                bridge->key_list = NULL;
@@ -211,19 +214,38 @@ 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(
-                               phys_to_virt(bridge->scratch_page_real));
+                               gart_to_virt(bridge->scratch_page_real));
 }
 
-/* XXX Kludge alert: agpgart isn't ready for multiple bridges yet */
+/* When we remove the global variable agp_bridge from all drivers
+ * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
+ */
+
 struct agp_bridge_data *agp_alloc_bridge(void)
 {
-       return agp_bridge;
+       struct agp_bridge_data *bridge = kmalloc(sizeof(*bridge), GFP_KERNEL);
+
+       if (!bridge)
+               return NULL;
+
+       memset(bridge, 0, sizeof(*bridge));
+       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);
 
@@ -240,40 +262,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);
+
        }
 
-       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);
@@ -281,10 +301,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);
-       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);
@@ -302,7 +322,7 @@ static int __init agp_init(void)
        return 0;
 }
 
-void __exit agp_exit(void)
+static void __exit agp_exit(void)
 {
 }