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