11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * AGPGART driver backend routines. 31da177e4SLinus Torvalds * Copyright (C) 2004 Silicon Graphics, Inc. 41da177e4SLinus Torvalds * Copyright (C) 2002-2003 Dave Jones. 51da177e4SLinus Torvalds * Copyright (C) 1999 Jeff Hartmann. 61da177e4SLinus Torvalds * Copyright (C) 1999 Precision Insight, Inc. 71da177e4SLinus Torvalds * Copyright (C) 1999 Xi Graphics, Inc. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Permission is hereby granted, free of charge, to any person obtaining a 101da177e4SLinus Torvalds * copy of this software and associated documentation files (the "Software"), 111da177e4SLinus Torvalds * to deal in the Software without restriction, including without limitation 121da177e4SLinus Torvalds * the rights to use, copy, modify, merge, publish, distribute, sublicense, 131da177e4SLinus Torvalds * and/or sell copies of the Software, and to permit persons to whom the 141da177e4SLinus Torvalds * Software is furnished to do so, subject to the following conditions: 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * The above copyright notice and this permission notice shall be included 171da177e4SLinus Torvalds * in all copies or substantial portions of the Software. 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 201da177e4SLinus Torvalds * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 211da177e4SLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 221da177e4SLinus Torvalds * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 231da177e4SLinus Torvalds * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 241da177e4SLinus Torvalds * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 251da177e4SLinus Torvalds * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * TODO: 281da177e4SLinus Torvalds * - Allocate more than order 0 pages to avoid too much linear map splitting. 291da177e4SLinus Torvalds */ 301da177e4SLinus Torvalds #include <linux/module.h> 311da177e4SLinus Torvalds #include <linux/pci.h> 321da177e4SLinus Torvalds #include <linux/init.h> 33*5a0e3ad6STejun Heo #include <linux/slab.h> 341da177e4SLinus Torvalds #include <linux/pagemap.h> 351da177e4SLinus Torvalds #include <linux/miscdevice.h> 361da177e4SLinus Torvalds #include <linux/pm.h> 371da177e4SLinus Torvalds #include <linux/agp_backend.h> 381da177e4SLinus Torvalds #include <linux/agpgart.h> 391da177e4SLinus Torvalds #include <linux/vmalloc.h> 401da177e4SLinus Torvalds #include <asm/io.h> 411da177e4SLinus Torvalds #include "agp.h" 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /* Due to XFree86 brain-damage, we can't go to 1.0 until they 441da177e4SLinus Torvalds * fix some real stupidity. It's only by chance we can bump 451da177e4SLinus Torvalds * past 0.99 at all due to some boolean logic error. */ 461da177e4SLinus Torvalds #define AGPGART_VERSION_MAJOR 0 47a13af4b4SDave Airlie #define AGPGART_VERSION_MINOR 103 48e7745d4eSDave Jones static const struct agp_version agp_current_version = 491da177e4SLinus Torvalds { 501da177e4SLinus Torvalds .major = AGPGART_VERSION_MAJOR, 511da177e4SLinus Torvalds .minor = AGPGART_VERSION_MINOR, 521da177e4SLinus Torvalds }; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) = 551da177e4SLinus Torvalds &agp_generic_find_bridge; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds struct agp_bridge_data *agp_bridge; 581da177e4SLinus Torvalds LIST_HEAD(agp_bridges); 591da177e4SLinus Torvalds EXPORT_SYMBOL(agp_bridge); 601da177e4SLinus Torvalds EXPORT_SYMBOL(agp_bridges); 611da177e4SLinus Torvalds EXPORT_SYMBOL(agp_find_bridge); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /** 641da177e4SLinus Torvalds * agp_backend_acquire - attempt to acquire an agp backend. 651da177e4SLinus Torvalds * 661da177e4SLinus Torvalds */ 671da177e4SLinus Torvalds struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds struct agp_bridge_data *bridge; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds bridge = agp_find_bridge(pdev); 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds if (!bridge) 741da177e4SLinus Torvalds return NULL; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds if (atomic_read(&bridge->agp_in_use)) 771da177e4SLinus Torvalds return NULL; 781da177e4SLinus Torvalds atomic_inc(&bridge->agp_in_use); 791da177e4SLinus Torvalds return bridge; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds EXPORT_SYMBOL(agp_backend_acquire); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /** 851da177e4SLinus Torvalds * agp_backend_release - release the lock on the agp backend. 861da177e4SLinus Torvalds * 871da177e4SLinus Torvalds * The caller must insure that the graphics aperture translation table 881da177e4SLinus Torvalds * is read for use by another entity. 891da177e4SLinus Torvalds * 901da177e4SLinus Torvalds * (Ensure that all memory it bound is unbound.) 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds void agp_backend_release(struct agp_bridge_data *bridge) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds if (bridge) 961da177e4SLinus Torvalds atomic_dec(&bridge->agp_in_use); 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds EXPORT_SYMBOL(agp_backend_release); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds 1015e9ad06aSDave Jones static const struct { int mem, agp; } maxes_table[] = { 1021da177e4SLinus Torvalds {0, 0}, 1031da177e4SLinus Torvalds {32, 4}, 1041da177e4SLinus Torvalds {64, 28}, 1051da177e4SLinus Torvalds {128, 96}, 1061da177e4SLinus Torvalds {256, 204}, 1071da177e4SLinus Torvalds {512, 440}, 1081da177e4SLinus Torvalds {1024, 942}, 1091da177e4SLinus Torvalds {2048, 1920}, 1101da177e4SLinus Torvalds {4096, 3932} 1111da177e4SLinus Torvalds }; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static int agp_find_max(void) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds long memory, index, result; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds #if PAGE_SHIFT < 20 1184481374cSJan Beulich memory = totalram_pages >> (20 - PAGE_SHIFT); 1191da177e4SLinus Torvalds #else 1204481374cSJan Beulich memory = totalram_pages << (PAGE_SHIFT - 20); 1211da177e4SLinus Torvalds #endif 1221da177e4SLinus Torvalds index = 1; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds while ((memory > maxes_table[index].mem) && (index < 8)) 1251da177e4SLinus Torvalds index++; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds result = maxes_table[index - 1].agp + 1281da177e4SLinus Torvalds ( (memory - maxes_table[index - 1].mem) * 1291da177e4SLinus Torvalds (maxes_table[index].agp - maxes_table[index - 1].agp)) / 1301da177e4SLinus Torvalds (maxes_table[index].mem - maxes_table[index - 1].mem); 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds result = result << (20 - PAGE_SHIFT); 1331da177e4SLinus Torvalds return result; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds static int agp_backend_initialize(struct agp_bridge_data *bridge) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds int size_value, rc, got_gatt=0, got_keylist=0; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds bridge->max_memory_agp = agp_find_max(); 1421da177e4SLinus Torvalds bridge->version = &agp_current_version; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if (bridge->driver->needs_scratch_page) { 14507613ba2SDave Airlie struct page *page = bridge->driver->agp_alloc_page(bridge); 1461da177e4SLinus Torvalds 14707613ba2SDave Airlie if (!page) { 148e3cf6951SBjorn Helgaas dev_err(&bridge->dev->dev, 149e3cf6951SBjorn Helgaas "can't get memory for scratch page\n"); 1501da177e4SLinus Torvalds return -ENOMEM; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 153c2980d8cSDavid Woodhouse bridge->scratch_page_page = page; 15456ec4c1eSDavid Woodhouse if (bridge->driver->agp_map_page) { 155c2980d8cSDavid Woodhouse if (bridge->driver->agp_map_page(page, 156ff663cf8SZhenyu Wang &bridge->scratch_page_dma)) { 157ff663cf8SZhenyu Wang dev_err(&bridge->dev->dev, 158ff663cf8SZhenyu Wang "unable to dma-map scratch page\n"); 159ff663cf8SZhenyu Wang rc = -ENOMEM; 160ff663cf8SZhenyu Wang goto err_out_nounmap; 161ff663cf8SZhenyu Wang } 16256ec4c1eSDavid Woodhouse } else { 1636a12235cSDavid Woodhouse bridge->scratch_page_dma = page_to_phys(page); 16456ec4c1eSDavid Woodhouse } 16556ec4c1eSDavid Woodhouse 16656ec4c1eSDavid Woodhouse bridge->scratch_page = bridge->driver->mask_memory(bridge, 16756ec4c1eSDavid Woodhouse bridge->scratch_page_dma, 0); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds size_value = bridge->driver->fetch_size(); 1711da177e4SLinus Torvalds if (size_value == 0) { 172e3cf6951SBjorn Helgaas dev_err(&bridge->dev->dev, "can't determine aperture size\n"); 1731da177e4SLinus Torvalds rc = -EINVAL; 1741da177e4SLinus Torvalds goto err_out; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds if (bridge->driver->create_gatt_table(bridge)) { 177e3cf6951SBjorn Helgaas dev_err(&bridge->dev->dev, 178e3cf6951SBjorn Helgaas "can't get memory for graphics translation table\n"); 1791da177e4SLinus Torvalds rc = -ENOMEM; 1801da177e4SLinus Torvalds goto err_out; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds got_gatt = 1; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds bridge->key_list = vmalloc(PAGE_SIZE * 4); 1851da177e4SLinus Torvalds if (bridge->key_list == NULL) { 186e3cf6951SBjorn Helgaas dev_err(&bridge->dev->dev, 187e3cf6951SBjorn Helgaas "can't allocate memory for key lists\n"); 1881da177e4SLinus Torvalds rc = -ENOMEM; 1891da177e4SLinus Torvalds goto err_out; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds got_keylist = 1; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* FIXME vmalloc'd memory not guaranteed contiguous */ 1941da177e4SLinus Torvalds memset(bridge->key_list, 0, PAGE_SIZE * 4); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds if (bridge->driver->configure()) { 197e3cf6951SBjorn Helgaas dev_err(&bridge->dev->dev, "error configuring host chipset\n"); 1981da177e4SLinus Torvalds rc = -EINVAL; 1991da177e4SLinus Torvalds goto err_out; 2001da177e4SLinus Torvalds } 201a8c84df9SKeith Packard INIT_LIST_HEAD(&bridge->mapped_list); 202a8c84df9SKeith Packard spin_lock_init(&bridge->mapped_lock); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds return 0; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds err_out: 207ff663cf8SZhenyu Wang if (bridge->driver->needs_scratch_page && 208ff663cf8SZhenyu Wang bridge->driver->agp_unmap_page) { 209c2980d8cSDavid Woodhouse bridge->driver->agp_unmap_page(bridge->scratch_page_page, 210c2980d8cSDavid Woodhouse bridge->scratch_page_dma); 211ff663cf8SZhenyu Wang } 212ff663cf8SZhenyu Wang err_out_nounmap: 21388d51967SAlan Hourihane if (bridge->driver->needs_scratch_page) { 214c2980d8cSDavid Woodhouse void *va = page_address(bridge->scratch_page_page); 215da503fa6SJan Beulich 216da503fa6SJan Beulich bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP); 217da503fa6SJan Beulich bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE); 21888d51967SAlan Hourihane } 2191da177e4SLinus Torvalds if (got_gatt) 2201da177e4SLinus Torvalds bridge->driver->free_gatt_table(bridge); 2211da177e4SLinus Torvalds if (got_keylist) { 2221da177e4SLinus Torvalds vfree(bridge->key_list); 2231da177e4SLinus Torvalds bridge->key_list = NULL; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds return rc; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /* cannot be __exit b/c as it could be called from __init code */ 2291da177e4SLinus Torvalds static void agp_backend_cleanup(struct agp_bridge_data *bridge) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds if (bridge->driver->cleanup) 2321da177e4SLinus Torvalds bridge->driver->cleanup(); 2331da177e4SLinus Torvalds if (bridge->driver->free_gatt_table) 2341da177e4SLinus Torvalds bridge->driver->free_gatt_table(bridge); 235f9101210SJesper Juhl 2361da177e4SLinus Torvalds vfree(bridge->key_list); 2371da177e4SLinus Torvalds bridge->key_list = NULL; 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds if (bridge->driver->agp_destroy_page && 24088d51967SAlan Hourihane bridge->driver->needs_scratch_page) { 241c2980d8cSDavid Woodhouse void *va = page_address(bridge->scratch_page_page); 242da503fa6SJan Beulich 243ff663cf8SZhenyu Wang if (bridge->driver->agp_unmap_page) 244c2980d8cSDavid Woodhouse bridge->driver->agp_unmap_page(bridge->scratch_page_page, 245ff663cf8SZhenyu Wang bridge->scratch_page_dma); 246ff663cf8SZhenyu Wang 247da503fa6SJan Beulich bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP); 248da503fa6SJan Beulich bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE); 24988d51967SAlan Hourihane } 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* When we remove the global variable agp_bridge from all drivers 2531da177e4SLinus Torvalds * then agp_alloc_bridge and agp_generic_find_bridge need to be updated 2541da177e4SLinus Torvalds */ 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds struct agp_bridge_data *agp_alloc_bridge(void) 2571da177e4SLinus Torvalds { 2580ea27d9fSDave Jones struct agp_bridge_data *bridge; 2591da177e4SLinus Torvalds 2600ea27d9fSDave Jones bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); 2611da177e4SLinus Torvalds if (!bridge) 2621da177e4SLinus Torvalds return NULL; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds atomic_set(&bridge->agp_in_use, 0); 2651da177e4SLinus Torvalds atomic_set(&bridge->current_memory_agp, 0); 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds if (list_empty(&agp_bridges)) 2681da177e4SLinus Torvalds agp_bridge = bridge; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds return bridge; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds EXPORT_SYMBOL(agp_alloc_bridge); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds void agp_put_bridge(struct agp_bridge_data *bridge) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds kfree(bridge); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds if (list_empty(&agp_bridges)) 2801da177e4SLinus Torvalds agp_bridge = NULL; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds EXPORT_SYMBOL(agp_put_bridge); 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds int agp_add_bridge(struct agp_bridge_data *bridge) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds int error; 2881da177e4SLinus Torvalds 2893f50b022SKevin Winchester if (agp_off) { 2903f50b022SKevin Winchester error = -ENODEV; 2913f50b022SKevin Winchester goto err_put_bridge; 2923f50b022SKevin Winchester } 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds if (!bridge->dev) { 2951da177e4SLinus Torvalds printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n"); 2963f50b022SKevin Winchester error = -EINVAL; 2973f50b022SKevin Winchester goto err_put_bridge; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* Grab reference on the chipset driver. */ 3011da177e4SLinus Torvalds if (!try_module_get(bridge->driver->owner)) { 302e3cf6951SBjorn Helgaas dev_info(&bridge->dev->dev, "can't lock chipset driver\n"); 3033f50b022SKevin Winchester error = -EINVAL; 3043f50b022SKevin Winchester goto err_put_bridge; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds error = agp_backend_initialize(bridge); 3081da177e4SLinus Torvalds if (error) { 309e3cf6951SBjorn Helgaas dev_info(&bridge->dev->dev, 310e3cf6951SBjorn Helgaas "agp_backend_initialize() failed\n"); 3111da177e4SLinus Torvalds goto err_out; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds if (list_empty(&agp_bridges)) { 3151da177e4SLinus Torvalds error = agp_frontend_initialize(); 3161da177e4SLinus Torvalds if (error) { 317e3cf6951SBjorn Helgaas dev_info(&bridge->dev->dev, 318e3cf6951SBjorn Helgaas "agp_frontend_initialize() failed\n"); 3191da177e4SLinus Torvalds goto frontend_err; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 322e3cf6951SBjorn Helgaas dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n", 3231da177e4SLinus Torvalds bridge->driver->fetch_size(), bridge->gart_bus_addr); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds list_add(&bridge->list, &agp_bridges); 3281da177e4SLinus Torvalds return 0; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds frontend_err: 3311da177e4SLinus Torvalds agp_backend_cleanup(bridge); 3321da177e4SLinus Torvalds err_out: 3331da177e4SLinus Torvalds module_put(bridge->driver->owner); 3343f50b022SKevin Winchester err_put_bridge: 3351da177e4SLinus Torvalds agp_put_bridge(bridge); 3361da177e4SLinus Torvalds return error; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(agp_add_bridge); 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds void agp_remove_bridge(struct agp_bridge_data *bridge) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds agp_backend_cleanup(bridge); 3441da177e4SLinus Torvalds list_del(&bridge->list); 3451da177e4SLinus Torvalds if (list_empty(&agp_bridges)) 3461da177e4SLinus Torvalds agp_frontend_cleanup(); 3471da177e4SLinus Torvalds module_put(bridge->driver->owner); 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(agp_remove_bridge); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds int agp_off; 3521da177e4SLinus Torvalds int agp_try_unsupported_boot; 3531da177e4SLinus Torvalds EXPORT_SYMBOL(agp_off); 3541da177e4SLinus Torvalds EXPORT_SYMBOL(agp_try_unsupported_boot); 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds static int __init agp_init(void) 3571da177e4SLinus Torvalds { 3581da177e4SLinus Torvalds if (!agp_off) 35970e8992eSDave Jones printk(KERN_INFO "Linux agpgart interface v%d.%d\n", 3601da177e4SLinus Torvalds AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); 3611da177e4SLinus Torvalds return 0; 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 364408b664aSAdrian Bunk static void __exit agp_exit(void) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds #ifndef MODULE 3691da177e4SLinus Torvalds static __init int agp_setup(char *s) 3701da177e4SLinus Torvalds { 3711da177e4SLinus Torvalds if (!strcmp(s,"off")) 3721da177e4SLinus Torvalds agp_off = 1; 3731da177e4SLinus Torvalds if (!strcmp(s,"try_unsupported")) 3741da177e4SLinus Torvalds agp_try_unsupported_boot = 1; 3751da177e4SLinus Torvalds return 1; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds __setup("agp=", agp_setup); 3781da177e4SLinus Torvalds #endif 3791da177e4SLinus Torvalds 380f4432c5cSDave Jones MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 3811da177e4SLinus Torvalds MODULE_DESCRIPTION("AGP GART driver"); 3821da177e4SLinus Torvalds MODULE_LICENSE("GPL and additional rights"); 3831da177e4SLinus Torvalds MODULE_ALIAS_MISCDEV(AGPGART_MINOR); 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds module_init(agp_init); 3861da177e4SLinus Torvalds module_exit(agp_exit); 3871da177e4SLinus Torvalds 388