xref: /OK3568_Linux_fs/kernel/drivers/char/agp/backend.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * AGPGART driver backend routines.
3*4882a593Smuzhiyun  * Copyright (C) 2004 Silicon Graphics, Inc.
4*4882a593Smuzhiyun  * Copyright (C) 2002-2003 Dave Jones.
5*4882a593Smuzhiyun  * Copyright (C) 1999 Jeff Hartmann.
6*4882a593Smuzhiyun  * Copyright (C) 1999 Precision Insight, Inc.
7*4882a593Smuzhiyun  * Copyright (C) 1999 Xi Graphics, Inc.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
10*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
11*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
12*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
14*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included
17*4882a593Smuzhiyun  * in all copies or substantial portions of the Software.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20*4882a593Smuzhiyun  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22*4882a593Smuzhiyun  * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
23*4882a593Smuzhiyun  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24*4882a593Smuzhiyun  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25*4882a593Smuzhiyun  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * TODO:
28*4882a593Smuzhiyun  * - Allocate more than order 0 pages to avoid too much linear map splitting.
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun #include <linux/module.h>
31*4882a593Smuzhiyun #include <linux/pci.h>
32*4882a593Smuzhiyun #include <linux/init.h>
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun #include <linux/pagemap.h>
35*4882a593Smuzhiyun #include <linux/miscdevice.h>
36*4882a593Smuzhiyun #include <linux/pm.h>
37*4882a593Smuzhiyun #include <linux/agp_backend.h>
38*4882a593Smuzhiyun #include <linux/agpgart.h>
39*4882a593Smuzhiyun #include <linux/vmalloc.h>
40*4882a593Smuzhiyun #include <asm/io.h>
41*4882a593Smuzhiyun #include "agp.h"
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* Due to XFree86 brain-damage, we can't go to 1.0 until they
44*4882a593Smuzhiyun  * fix some real stupidity. It's only by chance we can bump
45*4882a593Smuzhiyun  * past 0.99 at all due to some boolean logic error. */
46*4882a593Smuzhiyun #define AGPGART_VERSION_MAJOR 0
47*4882a593Smuzhiyun #define AGPGART_VERSION_MINOR 103
48*4882a593Smuzhiyun static const struct agp_version agp_current_version =
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	.major = AGPGART_VERSION_MAJOR,
51*4882a593Smuzhiyun 	.minor = AGPGART_VERSION_MINOR,
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
55*4882a593Smuzhiyun 	&agp_generic_find_bridge;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun struct agp_bridge_data *agp_bridge;
58*4882a593Smuzhiyun LIST_HEAD(agp_bridges);
59*4882a593Smuzhiyun EXPORT_SYMBOL(agp_bridge);
60*4882a593Smuzhiyun EXPORT_SYMBOL(agp_bridges);
61*4882a593Smuzhiyun EXPORT_SYMBOL(agp_find_bridge);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /**
64*4882a593Smuzhiyun  *	agp_backend_acquire  -  attempt to acquire an agp backend.
65*4882a593Smuzhiyun  *
66*4882a593Smuzhiyun  */
agp_backend_acquire(struct pci_dev * pdev)67*4882a593Smuzhiyun struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct agp_bridge_data *bridge;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	bridge = agp_find_bridge(pdev);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	if (!bridge)
74*4882a593Smuzhiyun 		return NULL;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (atomic_read(&bridge->agp_in_use))
77*4882a593Smuzhiyun 		return NULL;
78*4882a593Smuzhiyun 	atomic_inc(&bridge->agp_in_use);
79*4882a593Smuzhiyun 	return bridge;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun EXPORT_SYMBOL(agp_backend_acquire);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /**
85*4882a593Smuzhiyun  *	agp_backend_release  -  release the lock on the agp backend.
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  *	The caller must insure that the graphics aperture translation table
88*4882a593Smuzhiyun  *	is read for use by another entity.
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  *	(Ensure that all memory it bound is unbound.)
91*4882a593Smuzhiyun  */
agp_backend_release(struct agp_bridge_data * bridge)92*4882a593Smuzhiyun void agp_backend_release(struct agp_bridge_data *bridge)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (bridge)
96*4882a593Smuzhiyun 		atomic_dec(&bridge->agp_in_use);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun EXPORT_SYMBOL(agp_backend_release);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static const struct { int mem, agp; } maxes_table[] = {
102*4882a593Smuzhiyun 	{0, 0},
103*4882a593Smuzhiyun 	{32, 4},
104*4882a593Smuzhiyun 	{64, 28},
105*4882a593Smuzhiyun 	{128, 96},
106*4882a593Smuzhiyun 	{256, 204},
107*4882a593Smuzhiyun 	{512, 440},
108*4882a593Smuzhiyun 	{1024, 942},
109*4882a593Smuzhiyun 	{2048, 1920},
110*4882a593Smuzhiyun 	{4096, 3932}
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
agp_find_max(void)113*4882a593Smuzhiyun static int agp_find_max(void)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	long memory, index, result;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #if PAGE_SHIFT < 20
118*4882a593Smuzhiyun 	memory = totalram_pages() >> (20 - PAGE_SHIFT);
119*4882a593Smuzhiyun #else
120*4882a593Smuzhiyun 	memory = totalram_pages() << (PAGE_SHIFT - 20);
121*4882a593Smuzhiyun #endif
122*4882a593Smuzhiyun 	index = 1;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	while ((memory > maxes_table[index].mem) && (index < 8))
125*4882a593Smuzhiyun 		index++;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	result = maxes_table[index - 1].agp +
128*4882a593Smuzhiyun 	   ( (memory - maxes_table[index - 1].mem)  *
129*4882a593Smuzhiyun 	     (maxes_table[index].agp - maxes_table[index - 1].agp)) /
130*4882a593Smuzhiyun 	   (maxes_table[index].mem - maxes_table[index - 1].mem);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	result = result << (20 - PAGE_SHIFT);
133*4882a593Smuzhiyun 	return result;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 
agp_backend_initialize(struct agp_bridge_data * bridge)137*4882a593Smuzhiyun static int agp_backend_initialize(struct agp_bridge_data *bridge)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	int size_value, rc, got_gatt=0, got_keylist=0;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	bridge->max_memory_agp = agp_find_max();
142*4882a593Smuzhiyun 	bridge->version = &agp_current_version;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (bridge->driver->needs_scratch_page) {
145*4882a593Smuzhiyun 		struct page *page = bridge->driver->agp_alloc_page(bridge);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 		if (!page) {
148*4882a593Smuzhiyun 			dev_err(&bridge->dev->dev,
149*4882a593Smuzhiyun 				"can't get memory for scratch page\n");
150*4882a593Smuzhiyun 			return -ENOMEM;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 		bridge->scratch_page_page = page;
154*4882a593Smuzhiyun 		bridge->scratch_page_dma = page_to_phys(page);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 		bridge->scratch_page = bridge->driver->mask_memory(bridge,
157*4882a593Smuzhiyun 						   bridge->scratch_page_dma, 0);
158*4882a593Smuzhiyun 	}
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	size_value = bridge->driver->fetch_size();
161*4882a593Smuzhiyun 	if (size_value == 0) {
162*4882a593Smuzhiyun 		dev_err(&bridge->dev->dev, "can't determine aperture size\n");
163*4882a593Smuzhiyun 		rc = -EINVAL;
164*4882a593Smuzhiyun 		goto err_out;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 	if (bridge->driver->create_gatt_table(bridge)) {
167*4882a593Smuzhiyun 		dev_err(&bridge->dev->dev,
168*4882a593Smuzhiyun 			"can't get memory for graphics translation table\n");
169*4882a593Smuzhiyun 		rc = -ENOMEM;
170*4882a593Smuzhiyun 		goto err_out;
171*4882a593Smuzhiyun 	}
172*4882a593Smuzhiyun 	got_gatt = 1;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	bridge->key_list = vzalloc(PAGE_SIZE * 4);
175*4882a593Smuzhiyun 	if (bridge->key_list == NULL) {
176*4882a593Smuzhiyun 		dev_err(&bridge->dev->dev,
177*4882a593Smuzhiyun 			"can't allocate memory for key lists\n");
178*4882a593Smuzhiyun 		rc = -ENOMEM;
179*4882a593Smuzhiyun 		goto err_out;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 	got_keylist = 1;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* FIXME vmalloc'd memory not guaranteed contiguous */
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (bridge->driver->configure()) {
186*4882a593Smuzhiyun 		dev_err(&bridge->dev->dev, "error configuring host chipset\n");
187*4882a593Smuzhiyun 		rc = -EINVAL;
188*4882a593Smuzhiyun 		goto err_out;
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 	INIT_LIST_HEAD(&bridge->mapped_list);
191*4882a593Smuzhiyun 	spin_lock_init(&bridge->mapped_lock);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun err_out:
196*4882a593Smuzhiyun 	if (bridge->driver->needs_scratch_page) {
197*4882a593Smuzhiyun 		struct page *page = bridge->scratch_page_page;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
200*4882a593Smuzhiyun 		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 	if (got_gatt)
203*4882a593Smuzhiyun 		bridge->driver->free_gatt_table(bridge);
204*4882a593Smuzhiyun 	if (got_keylist) {
205*4882a593Smuzhiyun 		vfree(bridge->key_list);
206*4882a593Smuzhiyun 		bridge->key_list = NULL;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 	return rc;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun /* cannot be __exit b/c as it could be called from __init code */
agp_backend_cleanup(struct agp_bridge_data * bridge)212*4882a593Smuzhiyun static void agp_backend_cleanup(struct agp_bridge_data *bridge)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	if (bridge->driver->cleanup)
215*4882a593Smuzhiyun 		bridge->driver->cleanup();
216*4882a593Smuzhiyun 	if (bridge->driver->free_gatt_table)
217*4882a593Smuzhiyun 		bridge->driver->free_gatt_table(bridge);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	vfree(bridge->key_list);
220*4882a593Smuzhiyun 	bridge->key_list = NULL;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (bridge->driver->agp_destroy_page &&
223*4882a593Smuzhiyun 	    bridge->driver->needs_scratch_page) {
224*4882a593Smuzhiyun 		struct page *page = bridge->scratch_page_page;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
227*4882a593Smuzhiyun 		bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun /* When we remove the global variable agp_bridge from all drivers
232*4882a593Smuzhiyun  * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
233*4882a593Smuzhiyun  */
234*4882a593Smuzhiyun 
agp_alloc_bridge(void)235*4882a593Smuzhiyun struct agp_bridge_data *agp_alloc_bridge(void)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct agp_bridge_data *bridge;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
240*4882a593Smuzhiyun 	if (!bridge)
241*4882a593Smuzhiyun 		return NULL;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	atomic_set(&bridge->agp_in_use, 0);
244*4882a593Smuzhiyun 	atomic_set(&bridge->current_memory_agp, 0);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (list_empty(&agp_bridges))
247*4882a593Smuzhiyun 		agp_bridge = bridge;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return bridge;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun EXPORT_SYMBOL(agp_alloc_bridge);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 
agp_put_bridge(struct agp_bridge_data * bridge)254*4882a593Smuzhiyun void agp_put_bridge(struct agp_bridge_data *bridge)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun         kfree(bridge);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun         if (list_empty(&agp_bridges))
259*4882a593Smuzhiyun                 agp_bridge = NULL;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun EXPORT_SYMBOL(agp_put_bridge);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 
agp_add_bridge(struct agp_bridge_data * bridge)264*4882a593Smuzhiyun int agp_add_bridge(struct agp_bridge_data *bridge)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	int error;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (agp_off) {
269*4882a593Smuzhiyun 		error = -ENODEV;
270*4882a593Smuzhiyun 		goto err_put_bridge;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (!bridge->dev) {
274*4882a593Smuzhiyun 		printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n");
275*4882a593Smuzhiyun 		error = -EINVAL;
276*4882a593Smuzhiyun 		goto err_put_bridge;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/* Grab reference on the chipset driver. */
280*4882a593Smuzhiyun 	if (!try_module_get(bridge->driver->owner)) {
281*4882a593Smuzhiyun 		dev_info(&bridge->dev->dev, "can't lock chipset driver\n");
282*4882a593Smuzhiyun 		error = -EINVAL;
283*4882a593Smuzhiyun 		goto err_put_bridge;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	error = agp_backend_initialize(bridge);
287*4882a593Smuzhiyun 	if (error) {
288*4882a593Smuzhiyun 		dev_info(&bridge->dev->dev,
289*4882a593Smuzhiyun 			 "agp_backend_initialize() failed\n");
290*4882a593Smuzhiyun 		goto err_out;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	if (list_empty(&agp_bridges)) {
294*4882a593Smuzhiyun 		error = agp_frontend_initialize();
295*4882a593Smuzhiyun 		if (error) {
296*4882a593Smuzhiyun 			dev_info(&bridge->dev->dev,
297*4882a593Smuzhiyun 				 "agp_frontend_initialize() failed\n");
298*4882a593Smuzhiyun 			goto frontend_err;
299*4882a593Smuzhiyun 		}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n",
302*4882a593Smuzhiyun 			 bridge->driver->fetch_size(), bridge->gart_bus_addr);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	list_add(&bridge->list, &agp_bridges);
307*4882a593Smuzhiyun 	return 0;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun frontend_err:
310*4882a593Smuzhiyun 	agp_backend_cleanup(bridge);
311*4882a593Smuzhiyun err_out:
312*4882a593Smuzhiyun 	module_put(bridge->driver->owner);
313*4882a593Smuzhiyun err_put_bridge:
314*4882a593Smuzhiyun 	agp_put_bridge(bridge);
315*4882a593Smuzhiyun 	return error;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(agp_add_bridge);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 
agp_remove_bridge(struct agp_bridge_data * bridge)320*4882a593Smuzhiyun void agp_remove_bridge(struct agp_bridge_data *bridge)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	agp_backend_cleanup(bridge);
323*4882a593Smuzhiyun 	list_del(&bridge->list);
324*4882a593Smuzhiyun 	if (list_empty(&agp_bridges))
325*4882a593Smuzhiyun 		agp_frontend_cleanup();
326*4882a593Smuzhiyun 	module_put(bridge->driver->owner);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(agp_remove_bridge);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun int agp_off;
331*4882a593Smuzhiyun int agp_try_unsupported_boot;
332*4882a593Smuzhiyun EXPORT_SYMBOL(agp_off);
333*4882a593Smuzhiyun EXPORT_SYMBOL(agp_try_unsupported_boot);
334*4882a593Smuzhiyun 
agp_init(void)335*4882a593Smuzhiyun static int __init agp_init(void)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	if (!agp_off)
338*4882a593Smuzhiyun 		printk(KERN_INFO "Linux agpgart interface v%d.%d\n",
339*4882a593Smuzhiyun 			AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
340*4882a593Smuzhiyun 	return 0;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
agp_exit(void)343*4882a593Smuzhiyun static void __exit agp_exit(void)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun #ifndef MODULE
agp_setup(char * s)348*4882a593Smuzhiyun static __init int agp_setup(char *s)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	if (!strcmp(s,"off"))
351*4882a593Smuzhiyun 		agp_off = 1;
352*4882a593Smuzhiyun 	if (!strcmp(s,"try_unsupported"))
353*4882a593Smuzhiyun 		agp_try_unsupported_boot = 1;
354*4882a593Smuzhiyun 	return 1;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun __setup("agp=", agp_setup);
357*4882a593Smuzhiyun #endif
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun MODULE_AUTHOR("Dave Jones, Jeff Hartmann");
360*4882a593Smuzhiyun MODULE_DESCRIPTION("AGP GART driver");
361*4882a593Smuzhiyun MODULE_LICENSE("GPL and additional rights");
362*4882a593Smuzhiyun MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun module_init(agp_init);
365*4882a593Smuzhiyun module_exit(agp_exit);
366*4882a593Smuzhiyun 
367