First import
[xorg_rtime.git] / xorg-server-1.4 / hw / kdrive / linux / agp.c
blob80fb7259becc4ac2834641ff4f315b48c2fd7f62
1 /*
2 * Abstraction of the AGP GART interface.
4 * This version is for both Linux and FreeBSD.
6 * Copyright © 2000-2001 Nokia Home Communications
7 * Copyright © 2000 VA Linux Systems, Inc.
9 All rights reserved.
11 Permission is hereby granted, free of charge, to any person obtaining
12 a copy of this software and associated documentation files (the
13 "Software"), to deal in the Software without restriction, including
14 without limitation the rights to use, copy, modify, merge, publish,
15 distribute, and/or sell copies of the Software, and to permit persons
16 to whom the Software is furnished to do so, provided that the above
17 copyright notice(s) and this permission notice appear in all copies of
18 the Software and that both the above copyright notice(s) and this
19 permission notice appear in supporting documentation.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
24 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25 HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
26 SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
27 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
28 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
29 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 Except as contained in this notice, the name of a copyright holder
32 shall not be used in advertising or otherwise to promote the sale, use
33 or other dealings in this Software without prior written authorization
34 of the copyright holder.
39 * Author: Pontus Lidman <pontus.lidman@nokia.com> (adaption to KDrive) and others
42 #ifdef HAVE_CONFIG_H
43 #include <kdrive-config.h>
44 #endif
45 #include <X11/X.h>
46 #include "misc.h"
48 #include <unistd.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <sys/ioctl.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <stdlib.h>
59 #include "agp.h"
61 #if defined(linux)
62 #include <asm/ioctl.h>
64 #include <linux/agpgart.h>
66 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
67 #include <sys/ioctl.h>
68 #include <sys/agpio.h>
69 #endif
71 #ifndef AGP_DEVICE
72 #define AGP_DEVICE "/dev/agpgart"
73 #endif
74 /* AGP page size is independent of the host page size. */
75 #ifndef AGP_PAGE_SIZE
76 #define AGP_PAGE_SIZE 4096
77 #endif
78 #define AGPGART_MAJOR_VERSION 0
79 #define AGPGART_MINOR_VERSION 99
81 static int gartFd = -1;
82 static int acquiredScreen = -1;
85 * Open /dev/agpgart. Keep it open until server exit.
88 static Bool
89 GARTInit(void)
91 static Bool initDone = FALSE;
92 struct _agp_info agpinf;
94 if (initDone)
95 return (gartFd != -1);
97 initDone = TRUE;
99 if (gartFd == -1)
100 gartFd = open(AGP_DEVICE, O_RDWR, 0);
101 else
102 return FALSE;
104 if (gartFd == -1) {
105 fprintf(stderr, "Unable to open " AGP_DEVICE " (%s)\n",
106 strerror(errno));
107 return FALSE;
110 KdAcquireGART(-1);
111 /* Check the kernel driver version. */
112 if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) {
113 fprintf(stderr, "GARTInit: AGPIOC_INFO failed (%s)\n",
114 strerror(errno));
115 close(gartFd);
116 gartFd = -1;
117 return FALSE;
119 KdReleaseGART(-1);
121 #if defined(linux)
122 /* Per Dave Jones, every effort will be made to keep the
123 * agpgart interface backwards compatible, so allow all
124 * future versions.
126 if (
127 #if (AGPGART_MAJOR_VERSION > 0) /* quiet compiler */
128 agpinf.version.major < AGPGART_MAJOR_VERSION ||
129 #endif
130 (agpinf.version.major == AGPGART_MAJOR_VERSION &&
131 agpinf.version.minor < AGPGART_MINOR_VERSION)) {
132 fprintf(stderr,
133 "Kernel agpgart driver version is not current"
134 " (%d.%d vs %d.%d)\n",
135 agpinf.version.major, agpinf.version.minor,
136 AGPGART_MAJOR_VERSION, AGPGART_MINOR_VERSION);
137 close(gartFd);
138 gartFd = -1;
139 return FALSE;
141 #endif
143 return TRUE;
146 Bool
147 KdAgpGARTSupported()
149 return GARTInit();
152 AgpInfoPtr
153 KdGetAGPInfo(int screenNum)
155 struct _agp_info agpinf;
156 AgpInfoPtr info;
158 if (!GARTInit())
159 return NULL;
162 if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) {
163 fprintf(stderr, "Failed to allocate AgpInfo\n");
164 return NULL;
167 if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) {
168 fprintf(stderr,
169 "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n",
170 strerror(errno));
171 return NULL;
174 info->bridgeId = agpinf.bridge_id;
175 info->agpMode = agpinf.agp_mode;
176 info->base = agpinf.aper_base;
177 info->size = agpinf.aper_size;
178 info->totalPages = agpinf.pg_total;
179 info->systemPages = agpinf.pg_system;
180 info->usedPages = agpinf.pg_used;
182 return info;
186 * XXX If multiple screens can acquire the GART, should we have a reference
187 * count instead of using acquiredScreen?
190 Bool
191 KdAcquireGART(int screenNum)
193 if (screenNum != -1 && !GARTInit())
194 return FALSE;
196 if (screenNum == -1 || acquiredScreen != screenNum) {
197 if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) {
198 fprintf(stderr,
199 "AGPIOC_ACQUIRE failed (%s)\n",
200 strerror(errno));
201 return FALSE;
203 acquiredScreen = screenNum;
206 return TRUE;
209 Bool
210 KdReleaseGART(int screenNum)
212 if (screenNum != -1 && !GARTInit())
213 return FALSE;
215 if (acquiredScreen == screenNum) {
216 if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) {
217 fprintf(stderr,
218 "AGPIOC_RELEASE failed (%s)\n",
219 strerror(errno));
220 return FALSE;
222 acquiredScreen = -1;
223 return TRUE;
225 return FALSE;
229 KdAllocateGARTMemory(int screenNum, unsigned long size, int type,
230 unsigned long *physical)
232 struct _agp_allocate alloc;
233 int pages;
236 * Allocates "size" bytes of GART memory (rounds up to the next
237 * page multiple) or type "type". A handle (key) for the allocated
238 * memory is returned. On error, the return value is -1.
241 if (!GARTInit() || acquiredScreen != screenNum)
242 return -1;
244 pages = (size / AGP_PAGE_SIZE);
245 if (size % AGP_PAGE_SIZE != 0)
246 pages++;
248 /* XXX check for pages == 0? */
250 alloc.pg_count = pages;
251 alloc.type = type;
253 if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) {
254 fprintf(stderr, "KdAllocateGARTMemory: "
255 "allocation of %d pages failed\n\t(%s)\n", pages,
256 strerror(errno));
257 return -1;
260 if (physical)
261 *physical = alloc.physical;
263 return alloc.key;
267 /* Bind GART memory with "key" at "offset" */
268 Bool
269 KdBindGARTMemory(int screenNum, int key, unsigned long offset)
271 struct _agp_bind bind;
272 int pageOffset;
274 if (!GARTInit() || acquiredScreen != screenNum)
275 return FALSE;
277 if (acquiredScreen != screenNum) {
278 fprintf(stderr,
279 "AGP not acquired by this screen\n");
280 return FALSE;
283 if (offset % AGP_PAGE_SIZE != 0) {
284 fprintf(stderr, "KdBindGARTMemory: "
285 "offset (0x%lx) is not page-aligned (%d)\n",
286 offset, AGP_PAGE_SIZE);
287 return FALSE;
289 pageOffset = offset / AGP_PAGE_SIZE;
291 bind.pg_start = pageOffset;
292 bind.key = key;
294 if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) {
295 fprintf(stderr, "KdBindGARTMemory: "
296 "binding of gart memory with key %d\n"
297 "\tat offset 0x%lx failed (%s)\n",
298 key, offset, strerror(errno));
299 return FALSE;
302 return TRUE;
306 /* Unbind GART memory with "key" */
307 Bool
308 KdUnbindGARTMemory(int screenNum, int key)
310 struct _agp_unbind unbind;
312 if (!GARTInit() || acquiredScreen != screenNum)
313 return FALSE;
315 if (acquiredScreen != screenNum) {
316 fprintf(stderr,
317 "AGP not acquired by this screen\n");
318 return FALSE;
321 unbind.priority = 0;
322 unbind.key = key;
324 if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) {
325 fprintf(stderr, "KdUnbindGARTMemory: "
326 "unbinding of gart memory with key %d "
327 "failed (%s)\n", key, strerror(errno));
328 return FALSE;
331 return TRUE;
335 /* XXX Interface may change. */
336 Bool
337 KdEnableAGP(int screenNum, CARD32 mode)
339 agp_setup setup;
341 if (!GARTInit() || acquiredScreen != screenNum)
342 return FALSE;
344 setup.agp_mode = mode;
345 if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) {
346 fprintf(stderr, "KdEnableAGP: "
347 "AGPIOC_SETUP with mode %ld failed (%s)\n",
348 mode, strerror(errno));
349 return FALSE;
352 return TRUE;