18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * AGPGART driver backend routines.
38c2ecf20Sopenharmony_ci * Copyright (C) 2004 Silicon Graphics, Inc.
48c2ecf20Sopenharmony_ci * Copyright (C) 2002-2003 Dave Jones.
58c2ecf20Sopenharmony_ci * Copyright (C) 1999 Jeff Hartmann.
68c2ecf20Sopenharmony_ci * Copyright (C) 1999 Precision Insight, Inc.
78c2ecf20Sopenharmony_ci * Copyright (C) 1999 Xi Graphics, Inc.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
108c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
118c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
128c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
138c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
148c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included
178c2ecf20Sopenharmony_ci * in all copies or substantial portions of the Software.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
208c2ecf20Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
228c2ecf20Sopenharmony_ci * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
238c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
248c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
258c2ecf20Sopenharmony_ci * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * TODO:
288c2ecf20Sopenharmony_ci * - Allocate more than order 0 pages to avoid too much linear map splitting.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci#include <linux/module.h>
318c2ecf20Sopenharmony_ci#include <linux/pci.h>
328c2ecf20Sopenharmony_ci#include <linux/init.h>
338c2ecf20Sopenharmony_ci#include <linux/slab.h>
348c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
358c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
368c2ecf20Sopenharmony_ci#include <linux/pm.h>
378c2ecf20Sopenharmony_ci#include <linux/agp_backend.h>
388c2ecf20Sopenharmony_ci#include <linux/agpgart.h>
398c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
408c2ecf20Sopenharmony_ci#include <asm/io.h>
418c2ecf20Sopenharmony_ci#include "agp.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* Due to XFree86 brain-damage, we can't go to 1.0 until they
448c2ecf20Sopenharmony_ci * fix some real stupidity. It's only by chance we can bump
458c2ecf20Sopenharmony_ci * past 0.99 at all due to some boolean logic error. */
468c2ecf20Sopenharmony_ci#define AGPGART_VERSION_MAJOR 0
478c2ecf20Sopenharmony_ci#define AGPGART_VERSION_MINOR 103
488c2ecf20Sopenharmony_cistatic const struct agp_version agp_current_version =
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	.major = AGPGART_VERSION_MAJOR,
518c2ecf20Sopenharmony_ci	.minor = AGPGART_VERSION_MINOR,
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
558c2ecf20Sopenharmony_ci	&agp_generic_find_bridge;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct agp_bridge_data *agp_bridge;
588c2ecf20Sopenharmony_ciLIST_HEAD(agp_bridges);
598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_bridge);
608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_bridges);
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_find_bridge);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/**
648c2ecf20Sopenharmony_ci *	agp_backend_acquire  -  attempt to acquire an agp backend.
658c2ecf20Sopenharmony_ci *
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistruct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct agp_bridge_data *bridge;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	bridge = agp_find_bridge(pdev);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (!bridge)
748c2ecf20Sopenharmony_ci		return NULL;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (atomic_read(&bridge->agp_in_use))
778c2ecf20Sopenharmony_ci		return NULL;
788c2ecf20Sopenharmony_ci	atomic_inc(&bridge->agp_in_use);
798c2ecf20Sopenharmony_ci	return bridge;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_backend_acquire);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/**
858c2ecf20Sopenharmony_ci *	agp_backend_release  -  release the lock on the agp backend.
868c2ecf20Sopenharmony_ci *
878c2ecf20Sopenharmony_ci *	The caller must insure that the graphics aperture translation table
888c2ecf20Sopenharmony_ci *	is read for use by another entity.
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci *	(Ensure that all memory it bound is unbound.)
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_civoid agp_backend_release(struct agp_bridge_data *bridge)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (bridge)
968c2ecf20Sopenharmony_ci		atomic_dec(&bridge->agp_in_use);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_backend_release);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct { int mem, agp; } maxes_table[] = {
1028c2ecf20Sopenharmony_ci	{0, 0},
1038c2ecf20Sopenharmony_ci	{32, 4},
1048c2ecf20Sopenharmony_ci	{64, 28},
1058c2ecf20Sopenharmony_ci	{128, 96},
1068c2ecf20Sopenharmony_ci	{256, 204},
1078c2ecf20Sopenharmony_ci	{512, 440},
1088c2ecf20Sopenharmony_ci	{1024, 942},
1098c2ecf20Sopenharmony_ci	{2048, 1920},
1108c2ecf20Sopenharmony_ci	{4096, 3932}
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int agp_find_max(void)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	long memory, index, result;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#if PAGE_SHIFT < 20
1188c2ecf20Sopenharmony_ci	memory = totalram_pages() >> (20 - PAGE_SHIFT);
1198c2ecf20Sopenharmony_ci#else
1208c2ecf20Sopenharmony_ci	memory = totalram_pages() << (PAGE_SHIFT - 20);
1218c2ecf20Sopenharmony_ci#endif
1228c2ecf20Sopenharmony_ci	index = 1;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	while ((memory > maxes_table[index].mem) && (index < 8))
1258c2ecf20Sopenharmony_ci		index++;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	result = maxes_table[index - 1].agp +
1288c2ecf20Sopenharmony_ci	   ( (memory - maxes_table[index - 1].mem)  *
1298c2ecf20Sopenharmony_ci	     (maxes_table[index].agp - maxes_table[index - 1].agp)) /
1308c2ecf20Sopenharmony_ci	   (maxes_table[index].mem - maxes_table[index - 1].mem);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	result = result << (20 - PAGE_SHIFT);
1338c2ecf20Sopenharmony_ci	return result;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int agp_backend_initialize(struct agp_bridge_data *bridge)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	int size_value, rc, got_gatt=0, got_keylist=0;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	bridge->max_memory_agp = agp_find_max();
1428c2ecf20Sopenharmony_ci	bridge->version = &agp_current_version;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (bridge->driver->needs_scratch_page) {
1458c2ecf20Sopenharmony_ci		struct page *page = bridge->driver->agp_alloc_page(bridge);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		if (!page) {
1488c2ecf20Sopenharmony_ci			dev_err(&bridge->dev->dev,
1498c2ecf20Sopenharmony_ci				"can't get memory for scratch page\n");
1508c2ecf20Sopenharmony_ci			return -ENOMEM;
1518c2ecf20Sopenharmony_ci		}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		bridge->scratch_page_page = page;
1548c2ecf20Sopenharmony_ci		bridge->scratch_page_dma = page_to_phys(page);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		bridge->scratch_page = bridge->driver->mask_memory(bridge,
1578c2ecf20Sopenharmony_ci						   bridge->scratch_page_dma, 0);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	size_value = bridge->driver->fetch_size();
1618c2ecf20Sopenharmony_ci	if (size_value == 0) {
1628c2ecf20Sopenharmony_ci		dev_err(&bridge->dev->dev, "can't determine aperture size\n");
1638c2ecf20Sopenharmony_ci		rc = -EINVAL;
1648c2ecf20Sopenharmony_ci		goto err_out;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci	if (bridge->driver->create_gatt_table(bridge)) {
1678c2ecf20Sopenharmony_ci		dev_err(&bridge->dev->dev,
1688c2ecf20Sopenharmony_ci			"can't get memory for graphics translation table\n");
1698c2ecf20Sopenharmony_ci		rc = -ENOMEM;
1708c2ecf20Sopenharmony_ci		goto err_out;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci	got_gatt = 1;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	bridge->key_list = vzalloc(PAGE_SIZE * 4);
1758c2ecf20Sopenharmony_ci	if (bridge->key_list == NULL) {
1768c2ecf20Sopenharmony_ci		dev_err(&bridge->dev->dev,
1778c2ecf20Sopenharmony_ci			"can't allocate memory for key lists\n");
1788c2ecf20Sopenharmony_ci		rc = -ENOMEM;
1798c2ecf20Sopenharmony_ci		goto err_out;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci	got_keylist = 1;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* FIXME vmalloc'd memory not guaranteed contiguous */
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (bridge->driver->configure()) {
1868c2ecf20Sopenharmony_ci		dev_err(&bridge->dev->dev, "error configuring host chipset\n");
1878c2ecf20Sopenharmony_ci		rc = -EINVAL;
1888c2ecf20Sopenharmony_ci		goto err_out;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bridge->mapped_list);
1918c2ecf20Sopenharmony_ci	spin_lock_init(&bridge->mapped_lock);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return 0;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cierr_out:
1968c2ecf20Sopenharmony_ci	if (bridge->driver->needs_scratch_page) {
1978c2ecf20Sopenharmony_ci		struct page *page = bridge->scratch_page_page;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
2008c2ecf20Sopenharmony_ci		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	if (got_gatt)
2038c2ecf20Sopenharmony_ci		bridge->driver->free_gatt_table(bridge);
2048c2ecf20Sopenharmony_ci	if (got_keylist) {
2058c2ecf20Sopenharmony_ci		vfree(bridge->key_list);
2068c2ecf20Sopenharmony_ci		bridge->key_list = NULL;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci	return rc;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci/* cannot be __exit b/c as it could be called from __init code */
2128c2ecf20Sopenharmony_cistatic void agp_backend_cleanup(struct agp_bridge_data *bridge)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	if (bridge->driver->cleanup)
2158c2ecf20Sopenharmony_ci		bridge->driver->cleanup();
2168c2ecf20Sopenharmony_ci	if (bridge->driver->free_gatt_table)
2178c2ecf20Sopenharmony_ci		bridge->driver->free_gatt_table(bridge);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	vfree(bridge->key_list);
2208c2ecf20Sopenharmony_ci	bridge->key_list = NULL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (bridge->driver->agp_destroy_page &&
2238c2ecf20Sopenharmony_ci	    bridge->driver->needs_scratch_page) {
2248c2ecf20Sopenharmony_ci		struct page *page = bridge->scratch_page_page;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
2278c2ecf20Sopenharmony_ci		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* When we remove the global variable agp_bridge from all drivers
2328c2ecf20Sopenharmony_ci * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistruct agp_bridge_data *agp_alloc_bridge(void)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct agp_bridge_data *bridge;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
2408c2ecf20Sopenharmony_ci	if (!bridge)
2418c2ecf20Sopenharmony_ci		return NULL;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	atomic_set(&bridge->agp_in_use, 0);
2448c2ecf20Sopenharmony_ci	atomic_set(&bridge->current_memory_agp, 0);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (list_empty(&agp_bridges))
2478c2ecf20Sopenharmony_ci		agp_bridge = bridge;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	return bridge;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_alloc_bridge);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_civoid agp_put_bridge(struct agp_bridge_data *bridge)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci        kfree(bridge);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci        if (list_empty(&agp_bridges))
2598c2ecf20Sopenharmony_ci                agp_bridge = NULL;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_put_bridge);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint agp_add_bridge(struct agp_bridge_data *bridge)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	int error;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (agp_off) {
2698c2ecf20Sopenharmony_ci		error = -ENODEV;
2708c2ecf20Sopenharmony_ci		goto err_put_bridge;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (!bridge->dev) {
2748c2ecf20Sopenharmony_ci		printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n");
2758c2ecf20Sopenharmony_ci		error = -EINVAL;
2768c2ecf20Sopenharmony_ci		goto err_put_bridge;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* Grab reference on the chipset driver. */
2808c2ecf20Sopenharmony_ci	if (!try_module_get(bridge->driver->owner)) {
2818c2ecf20Sopenharmony_ci		dev_info(&bridge->dev->dev, "can't lock chipset driver\n");
2828c2ecf20Sopenharmony_ci		error = -EINVAL;
2838c2ecf20Sopenharmony_ci		goto err_put_bridge;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	error = agp_backend_initialize(bridge);
2878c2ecf20Sopenharmony_ci	if (error) {
2888c2ecf20Sopenharmony_ci		dev_info(&bridge->dev->dev,
2898c2ecf20Sopenharmony_ci			 "agp_backend_initialize() failed\n");
2908c2ecf20Sopenharmony_ci		goto err_out;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (list_empty(&agp_bridges)) {
2948c2ecf20Sopenharmony_ci		error = agp_frontend_initialize();
2958c2ecf20Sopenharmony_ci		if (error) {
2968c2ecf20Sopenharmony_ci			dev_info(&bridge->dev->dev,
2978c2ecf20Sopenharmony_ci				 "agp_frontend_initialize() failed\n");
2988c2ecf20Sopenharmony_ci			goto frontend_err;
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n",
3028c2ecf20Sopenharmony_ci			 bridge->driver->fetch_size(), bridge->gart_bus_addr);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	list_add(&bridge->list, &agp_bridges);
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cifrontend_err:
3108c2ecf20Sopenharmony_ci	agp_backend_cleanup(bridge);
3118c2ecf20Sopenharmony_cierr_out:
3128c2ecf20Sopenharmony_ci	module_put(bridge->driver->owner);
3138c2ecf20Sopenharmony_cierr_put_bridge:
3148c2ecf20Sopenharmony_ci	agp_put_bridge(bridge);
3158c2ecf20Sopenharmony_ci	return error;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(agp_add_bridge);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_civoid agp_remove_bridge(struct agp_bridge_data *bridge)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	agp_backend_cleanup(bridge);
3238c2ecf20Sopenharmony_ci	list_del(&bridge->list);
3248c2ecf20Sopenharmony_ci	if (list_empty(&agp_bridges))
3258c2ecf20Sopenharmony_ci		agp_frontend_cleanup();
3268c2ecf20Sopenharmony_ci	module_put(bridge->driver->owner);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(agp_remove_bridge);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ciint agp_off;
3318c2ecf20Sopenharmony_ciint agp_try_unsupported_boot;
3328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_off);
3338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(agp_try_unsupported_boot);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int __init agp_init(void)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	if (!agp_off)
3388c2ecf20Sopenharmony_ci		printk(KERN_INFO "Linux agpgart interface v%d.%d\n",
3398c2ecf20Sopenharmony_ci			AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void __exit agp_exit(void)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci#ifndef MODULE
3488c2ecf20Sopenharmony_cistatic __init int agp_setup(char *s)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	if (!strcmp(s,"off"))
3518c2ecf20Sopenharmony_ci		agp_off = 1;
3528c2ecf20Sopenharmony_ci	if (!strcmp(s,"try_unsupported"))
3538c2ecf20Sopenharmony_ci		agp_try_unsupported_boot = 1;
3548c2ecf20Sopenharmony_ci	return 1;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci__setup("agp=", agp_setup);
3578c2ecf20Sopenharmony_ci#endif
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dave Jones, Jeff Hartmann");
3608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AGP GART driver");
3618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL and additional rights");
3628c2ecf20Sopenharmony_ciMODULE_ALIAS_MISCDEV(AGPGART_MINOR);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cimodule_init(agp_init);
3658c2ecf20Sopenharmony_cimodule_exit(agp_exit);
3668c2ecf20Sopenharmony_ci
367