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 51static int gartFd = -1; 52static int acquiredScreen = -1; 53static Bool initDone = FALSE; 54/* 55 * Close /dev/agpgart. This frees all associated memory allocated during 56 * this server generation. 57 */ 58Bool 59xf86GARTCloseScreen(int screenNum) 60{ 61 if (gartFd != -1) { 62 close(gartFd); 63 acquiredScreen = -1; 64 gartFd = -1; 65 initDone = FALSE; 66 67 xf86DrvMsg(screenNum, X_INFO, 68 "xf86GARTCloseScreen: device closed successfully\n"); 69 70 } 71 return TRUE; 72} 73 74/* 75 * Open /dev/agpgart. Keep it open until xf86GARTCloseScreen is called. 76 */ 77static Bool 78GARTInit(int screenNum) 79{ 80 if (initDone) 81 return gartFd != -1; 82 83 if (gartFd == -1) 84 gartFd = open(AGP_DEVICE, O_RDWR); 85 else 86 return FALSE; 87 88 if (gartFd == -1) { 89 xf86DrvMsg(screenNum, X_ERROR, 90 "GARTInit: Unable to open " AGP_DEVICE " (%s)\n", 91 strerror(errno)); 92 return FALSE; 93 } 94 95 initDone = TRUE; 96 xf86DrvMsg(screenNum, X_INFO, 97 "GARTInit: " AGP_DEVICE " opened successfully\n"); 98 99 return TRUE; 100} 101 102Bool 103xf86AgpGARTSupported(void) 104{ 105 return (GARTInit(-1)); 106 107} 108 109AgpInfoPtr 110xf86GetAGPInfo(int screenNum) 111{ 112 agp_info_t agpinf; 113 AgpInfoPtr info; 114 115 if (!GARTInit(screenNum)) 116 return NULL; 117 118 if (ioctl(gartFd, AGPIOC_INFO, &agpinf) != 0) { 119 xf86DrvMsg(screenNum, X_ERROR, 120 "xf86GetAGPInfo: AGPIOC_INFO failed (%s)\n", 121 strerror(errno)); 122 return NULL; 123 } 124 125 if ((info = calloc(sizeof(AgpInfo), 1)) == NULL) { 126 xf86DrvMsg(screenNum, X_ERROR, 127 "xf86GetAGPInfo: Failed to allocate AgpInfo\n"); 128 return NULL; 129 } 130 131 info->bridgeId = agpinf.agpi_devid; 132 info->agpMode = agpinf.agpi_mode; 133 info->base = agpinf.agpi_aperbase; 134 info->size = agpinf.agpi_apersize; 135 info->totalPages = (unsigned long)agpinf.agpi_pgtotal; 136 info->systemPages = (unsigned long)agpinf.agpi_pgsystem; 137 info->usedPages = (unsigned long)agpinf.agpi_pgused; 138 139 return info; 140} 141 142Bool 143xf86AcquireGART(int screenNum) 144{ 145 146 if (!GARTInit(screenNum)) 147 return FALSE; 148 149 if (acquiredScreen != screenNum) { 150 if (ioctl(gartFd, AGPIOC_ACQUIRE, 0) != 0) { 151 xf86DrvMsg(screenNum, X_WARNING, 152 "xf86AcquireGART: AGPIOC_ACQUIRE failed (%s)\n", 153 strerror(errno)); 154 return FALSE; 155 } 156 acquiredScreen = screenNum; 157 xf86DrvMsg(screenNum, X_INFO, 158 "xf86AcquireGART: AGPIOC_ACQUIRE succeeded\n"); 159 } 160 return TRUE; 161} 162 163Bool 164xf86ReleaseGART(int screenNum) 165{ 166 167 if (!GARTInit(screenNum)) 168 return FALSE; 169 170 if (acquiredScreen == screenNum) { 171 /* 172 * The FreeBSD agp driver removes allocations on release. 173 * The Solaris driver doesn't. xf86ReleaseGART() is expected 174 * to give up access to the GART, but not to remove any 175 * allocations. 176 */ 177 178 if (ioctl(gartFd, AGPIOC_RELEASE, 0) != 0) { 179 xf86DrvMsg(screenNum, X_WARNING, 180 "xf86ReleaseGART: AGPIOC_RELEASE failed (%s)\n", 181 strerror(errno)); 182 return FALSE; 183 } 184 acquiredScreen = -1; 185 xf86DrvMsg(screenNum, X_INFO, 186 "xf86ReleaseGART: AGPIOC_RELEASE succeeded\n"); 187 return TRUE; 188 } 189 return FALSE; 190} 191 192int 193xf86AllocateGARTMemory(int screenNum, unsigned long size, int type, 194 unsigned long *physical) 195{ 196 agp_allocate_t alloc; 197 int pages; 198 199 /* 200 * Allocates "size" bytes of GART memory (rounds up to the next 201 * page multiple) or type "type". A handle (key) for the allocated 202 * memory is returned. On error, the return value is -1. 203 * "size" should be larger than 0, or AGPIOC_ALLOCATE ioctl will 204 * return error. 205 */ 206 207 if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) 208 return -1; 209 210 pages = (size / AGP_PAGE_SIZE); 211 if (size % AGP_PAGE_SIZE != 0) 212 pages++; 213 214 alloc.agpa_pgcount = pages; 215 alloc.agpa_type = type; 216 217 if (ioctl(gartFd, AGPIOC_ALLOCATE, &alloc) != 0) { 218 xf86DrvMsg(screenNum, X_WARNING, "xf86AllocateGARTMemory: " 219 "allocation of %d pages failed\n\t(%s)\n", pages, 220 strerror(errno)); 221 return -1; 222 } 223 224 if (physical) 225 *physical = (unsigned long)alloc.agpa_physical; 226 227 return alloc.agpa_key; 228} 229 230Bool 231xf86DeallocateGARTMemory(int screenNum, int key) 232{ 233 if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) 234 return FALSE; 235 236 if (ioctl(gartFd, AGPIOC_DEALLOCATE, (int *)key) != 0) { 237 xf86DrvMsg(screenNum, X_WARNING, "xf86DeAllocateGARTMemory: " 238 "deallocation of gart memory with key %d failed\n" 239 "\t(%s)\n", key, strerror(errno)); 240 return FALSE; 241 } 242 243 return TRUE; 244} 245 246/* Bind GART memory with "key" at "offset" */ 247Bool 248xf86BindGARTMemory(int screenNum, int key, unsigned long offset) 249{ 250 agp_bind_t bind; 251 int pageOffset; 252 253 if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) 254 return FALSE; 255 256 if (offset % AGP_PAGE_SIZE != 0) { 257 xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " 258 "offset (0x%lx) is not page-aligned (%d)\n", 259 offset, AGP_PAGE_SIZE); 260 return FALSE; 261 } 262 pageOffset = offset / AGP_PAGE_SIZE; 263 264 xf86DrvMsgVerb(screenNum, X_INFO, 3, 265 "xf86BindGARTMemory: bind key %d at 0x%08lx " 266 "(pgoffset %d)\n", key, offset, pageOffset); 267 268 bind.agpb_pgstart = pageOffset; 269 bind.agpb_key = key; 270 271 if (ioctl(gartFd, AGPIOC_BIND, &bind) != 0) { 272 xf86DrvMsg(screenNum, X_WARNING, "xf86BindGARTMemory: " 273 "binding of gart memory with key %d\n" 274 "\tat offset 0x%lx failed (%s)\n", 275 key, offset, strerror(errno)); 276 return FALSE; 277 } 278 279 return TRUE; 280} 281 282/* Unbind GART memory with "key" */ 283Bool 284xf86UnbindGARTMemory(int screenNum, int key) 285{ 286 agp_unbind_t unbind; 287 288 if (!GARTInit(screenNum) || (acquiredScreen != screenNum)) 289 return FALSE; 290 291 unbind.agpu_pri = 0; 292 unbind.agpu_key = key; 293 294 if (ioctl(gartFd, AGPIOC_UNBIND, &unbind) != 0) { 295 xf86DrvMsg(screenNum, X_WARNING, "xf86UnbindGARTMemory: " 296 "unbinding of gart memory with key %d " 297 "failed (%s)\n", key, strerror(errno)); 298 return FALSE; 299 } 300 301 xf86DrvMsgVerb(screenNum, X_INFO, 3, 302 "xf86UnbindGARTMemory: unbind key %d\n", key); 303 304 return TRUE; 305} 306 307 308/* XXX Interface may change. */ 309Bool 310xf86EnableAGP(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 328