xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/os-support/solaris/sun_agp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Abstraction of the AGP GART interface.
3  *
4  * This version is for Solaris.
5  *
6  * Copyright © 2000 VA Linux Systems, Inc.
7  * Copyright © 2001 The XFree86 Project, Inc.
8  */
9 /* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice (including the next
19  * paragraph) shall be included in all copies or substantial portions of the
20  * Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  */
30 
31 #ifdef HAVE_XORG_CONFIG_H
32 #include <xorg-config.h>
33 #endif
34 
35 #include <X11/X.h>
36 #include "xf86.h"
37 #include "xf86Priv.h"
38 #include "xf86_OSlib.h"
39 #include "xf86_OSproc.h"
40 #include <unistd.h>
41 #include <sys/ioccom.h>
42 #include <sys/types.h>
43 #include <fcntl.h>
44 #include <sys/agpgart.h>
45 
46 /* AGP page size is independent of the host page size. */
47 #ifndef	AGP_PAGE_SIZE
48 #define	AGP_PAGE_SIZE		4096
49 #endif
50 
51 static int gartFd = -1;
52 static int acquiredScreen = -1;
53 static Bool initDone = FALSE;
54 
55 /*
56  * Close /dev/agpgart.  This frees all associated memory allocated during
57  * this server generation.
58  */
59 Bool
xf86GARTCloseScreen(int screenNum)60 xf86GARTCloseScreen(int screenNum)
61 {
62     if (gartFd != -1) {
63         close(gartFd);
64         acquiredScreen = -1;
65         gartFd = -1;
66         initDone = FALSE;
67 
68         xf86DrvMsg(screenNum, X_INFO,
69                    "xf86GARTCloseScreen: device closed successfully\n");
70 
71     }
72     return TRUE;
73 }
74 
75 /*
76  * Open /dev/agpgart.  Keep it open until xf86GARTCloseScreen is called.
77  */
78 static Bool
GARTInit(int screenNum)79 GARTInit(int screenNum)
80 {
81     if (initDone)
82         return gartFd != -1;
83 
84     if (gartFd == -1)
85         gartFd = open(AGP_DEVICE, O_RDWR);
86     else
87         return FALSE;
88 
89     if (gartFd == -1) {
90         xf86DrvMsg(screenNum, X_ERROR,
91                    "GARTInit: Unable to open " AGP_DEVICE " (%s)\n",
92                    strerror(errno));
93         return FALSE;
94     }
95 
96     initDone = TRUE;
97     xf86DrvMsg(screenNum, X_INFO,
98                "GARTInit: " AGP_DEVICE " opened successfully\n");
99 
100     return TRUE;
101 }
102 
103 Bool
xf86AgpGARTSupported(void)104 xf86AgpGARTSupported(void)
105 {
106     return (GARTInit(-1));
107 
108 }
109 
110 AgpInfoPtr
xf86GetAGPInfo(int screenNum)111 xf86GetAGPInfo(int screenNum)
112 {
113     agp_info_t agpinf;
114     AgpInfoPtr info;
115 
116     if (!GARTInit(screenNum))
117         return NULL;
118 
119     if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) {
120         xf86DrvMsg(screenNum, X_ERROR,
121                    "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n",
122                    strerror(errno));
123         return NULL;
124     }
125 
126     if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) {
127         xf86DrvMsg(screenNum, X_ERROR,
128                    "xf86GetAGPInfo: Failed to allocate AgpInfo\n");
129         return NULL;
130     }
131 
132     info->bridgeId = agpinf.agpi_devid;
133     info->agpMode = agpinf.agpi_mode;
134     info->base = agpinf.agpi_aperbase;
135     info->size = agpinf.agpi_apersize;
136     info->totalPages = (unsigned long) agpinf.agpi_pgtotal;
137     info->systemPages = (unsigned long) agpinf.agpi_pgsystem;
138     info->usedPages = (unsigned long) agpinf.agpi_pgused;
139 
140     return info;
141 }
142 
143 Bool
xf86AcquireGART(int screenNum)144 xf86AcquireGART(int screenNum)
145 {
146 
147     if (!GARTInit(screenNum))
148         return FALSE;
149 
150     if (acquiredScreen != screenNum) {
151         if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) {
152             xf86DrvMsg(screenNum, X_WARNING,
153                        "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n",
154                        strerror(errno));
155             return FALSE;
156         }
157         acquiredScreen = screenNum;
158         xf86DrvMsg(screenNum, X_INFO,
159                    "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n");
160     }
161     return TRUE;
162 }
163 
164 Bool
xf86ReleaseGART(int screenNum)165 xf86ReleaseGART(int screenNum)
166 {
167 
168     if (!GARTInit(screenNum))
169         return FALSE;
170 
171     if (acquiredScreen == screenNum) {
172         /*
173          * The FreeBSD agp driver removes allocations on release.
174          * The Solaris driver doesn't.  xf86ReleaseGART() is expected
175          * to give up access to the GART, but not to remove any
176          * allocations.
177          */
178 
179         if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) {
180             xf86DrvMsg(screenNum, X_WARNING,
181                        "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n",
182                        strerror(errno));
183             return FALSE;
184         }
185         acquiredScreen = -1;
186         xf86DrvMsg(screenNum, X_INFO,
187                    "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n");
188         return TRUE;
189     }
190     return FALSE;
191 }
192 
193 int
xf86AllocateGARTMemory(int screenNum,unsigned long size,int type,unsigned long * physical)194 xf86AllocateGARTMemory(int screenNum, unsigned long size, int type,
195                        unsigned long *physical)
196 {
197     agp_allocate_t alloc;
198     int pages;
199 
200     /*
201      * Allocates "size" bytes of GART memory (rounds up to the next
202      * page multiple) or type "type".  A handle (key) for the allocated
203      * memory is returned.  On error, the return value is -1.
204      * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will
205      * return error.
206      */
207 
208     if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
209         return -1;
210 
211     pages = (size / AGP_PAGE_SIZE);
212     if (size % AGP_PAGE_SIZE != 0)
213         pages++;
214 
215     alloc.agpa_pgcount = pages;
216     alloc.agpa_type = type;
217 
218     if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) {
219         xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: "
220                    "allocation of %d pages failed\n\t(%s)\n", pages,
221                    strerror(errno));
222         return -1;
223     }
224 
225     if (physical)
226         *physical = (unsigned long) alloc.agpa_physical;
227 
228     return alloc.agpa_key;
229 }
230 
231 Bool
xf86DeallocateGARTMemory(int screenNum,int key)232 xf86DeallocateGARTMemory(int screenNum, int key)
233 {
234     if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
235         return FALSE;
236 
237     if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *) (uintptr_t) key) != 0) {
238         xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: "
239                    "deallocation of gart memory with key %d failed\n"
240                    "\t(%s)\n", key, strerror(errno));
241         return FALSE;
242     }
243 
244     return TRUE;
245 }
246 
247 /* Bind GART memory with "key" at "offset" */
248 Bool
xf86BindGARTMemory(int screenNum,int key,unsigned long offset)249 xf86BindGARTMemory(int screenNum, int key, unsigned long offset)
250 {
251     agp_bind_t bind;
252     int pageOffset;
253 
254     if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
255         return FALSE;
256 
257     if (offset % AGP_PAGE_SIZE != 0) {
258         xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: "
259                    "offset (0x%lx) is not page-aligned (%d)\n",
260                    offset, AGP_PAGE_SIZE);
261         return FALSE;
262     }
263     pageOffset = offset / AGP_PAGE_SIZE;
264 
265     xf86DrvMsgVerb(screenNum, X_INFO, 3,
266                    "xf86BindGARTMemory: bind key %d at 0x%08lx "
267                    "(pgoffset %d)\n", key, offset, pageOffset);
268 
269     bind.agpb_pgstart = pageOffset;
270     bind.agpb_key = key;
271 
272     if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) {
273         xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: "
274                    "binding of gart memory with key %d\n"
275                    "\tat offset 0x%lx failed (%s)\n",
276                    key, offset, strerror(errno));
277         return FALSE;
278     }
279 
280     return TRUE;
281 }
282 
283 /* Unbind GART memory with "key" */
284 Bool
xf86UnbindGARTMemory(int screenNum,int key)285 xf86UnbindGARTMemory(int screenNum, int key)
286 {
287     agp_unbind_t unbind;
288 
289     if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
290         return FALSE;
291 
292     unbind.agpu_pri = 0;
293     unbind.agpu_key = key;
294 
295     if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) {
296         xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: "
297                    "unbinding of gart memory with key %d "
298                    "failed (%s)\n", key, strerror(errno));
299         return FALSE;
300     }
301 
302     xf86DrvMsgVerb(screenNum, X_INFO, 3,
303                    "xf86UnbindGARTMemory: unbind key %d\n", key);
304 
305     return TRUE;
306 }
307 
308 /* XXX Interface may change. */
309 Bool
xf86EnableAGP(int screenNum,CARD32 mode)310 xf86EnableAGP(int screenNum, CARD32 mode)
311 {
312     agp_setup_t setup;
313 
314     if (!GARTInit(screenNum) || (acquiredScreen != screenNum))
315         return FALSE;
316 
317     setup.agps_mode = mode;
318     if (ioctl(gartFd, AGPIOC_SETUP, &setup) != 0) {
319         xf86DrvMsg(screenNum, X_WARNING, "xf86EnableAGP: "
320                    "AGPIOC_SETUP with mode %x failed (%s)\n",
321                    (unsigned int) mode, strerror(errno));
322         return FALSE;
323     }
324 
325     return TRUE;
326 }
327