1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*- 8 * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com 9 */ 10 /* 11 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 13 * All Rights Reserved. 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a 16 * copy of this software and associated documentation files (the "Software"), 17 * to deal in the Software without restriction, including without limitation 18 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 * and/or sell copies of the Software, and to permit persons to whom the 20 * Software is furnished to do so, subject to the following conditions: 21 * 22 * The above copyright notice and this permission notice (including the next 23 * paragraph) shall be included in all copies or substantial portions of the 24 * Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 29 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 30 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 31 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 32 * OTHER DEALINGS IN THE SOFTWARE. 33 * 34 * Author: 35 * Rickard E. (Rik) Faith <faith@valinux.com> 36 * Gareth Hughes <gareth@valinux.com> 37 * 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include "drm.h" 43 #include "drmP.h" 44 45 #ifndef AGP_PAGE_SIZE 46 #define AGP_PAGE_SIZE 4096 47 #define AGP_PAGE_SHIFT 12 48 #endif 49 50 /*ARGSUSED*/ 51 int 52 drm_device_is_agp(drm_softstate_t *dev) 53 { 54 return (1); 55 } 56 57 /*ARGSUSED*/ 58 int 59 drm_device_is_pcie(drm_softstate_t *dev) 60 { 61 return (0); 62 } 63 64 65 /*ARGSUSED*/ 66 int 67 drm_agp_info(DRM_IOCTL_ARGS) 68 { 69 DRM_DEVICE; 70 agp_info_t agpinf; 71 drm_agp_info_t info; 72 int ret, rval; 73 74 if (!dev->agp || !dev->agp->acquired) 75 return (-1); 76 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_INFO, 77 (intptr_t)&agpinf, FKIOCTL, kcred, 78 &rval); 79 if (ret) { 80 DRM_ERROR("drm_agp_info: AGPIOC_INFO failed"); 81 return (-1); 82 } 83 dev->agp->agp_info = agpinf; 84 info.agp_version_major = agpinf.agpi_version.agpv_major; 85 info.agp_version_minor = agpinf.agpi_version.agpv_minor; 86 info.mode = agpinf.agpi_mode; 87 info.aperture_base = agpinf.agpi_aperbase; 88 info.aperture_size = agpinf.agpi_apersize; 89 info.memory_allowed = agpinf.agpi_pgtotal; 90 info.memory_used = agpinf.agpi_pgused; 91 info.id_vendor = agpinf.agpi_devid & 0xffff; 92 info.id_device = agpinf.agpi_devid >> 16; 93 94 DRM_COPY_TO_USER_IOCTL((drm_agp_info_t *)data, 95 info, sizeof (info)); 96 return (0); 97 } 98 99 /*ARGSUSED*/ 100 int 101 drm_agp_acquire(DRM_IOCTL_ARGS) 102 { 103 DRM_DEVICE; 104 int ret, rval; 105 106 DRM_DEBUG("drm_agp_acquire\n"); 107 if (!dev->agp) { 108 DRM_ERROR(" drm_agp_acquire : dev->agp=NULL"); 109 return (-1); 110 } 111 112 if (ldi_open_by_name(AGP_DEVICE, FEXCL, kcred, 113 &dev->agpgart_hdl, dev->agpgart_li)) { 114 DRM_DEBUG("drm_agp_acquired: open /dev/agpgart failed"); 115 return (DDI_FAILURE); 116 } 117 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_ACQUIRE, 118 (uintptr_t)0, FKIOCTL, kcred, &rval); 119 if (ret) { 120 DRM_ERROR("drm_agp_acquired: AGPIOC_ACQUIRE failed\n"); 121 (void) ldi_close(dev->agpgart_hdl, FEXCL, kcred); 122 return (DDI_FAILURE); 123 } 124 DRM_DEBUG("drm_agp_acquired: Acquired\n"); 125 dev->agp->acquired = 1; 126 127 return (0); 128 } 129 130 /*ARGSUSED*/ 131 int 132 drm_agp_release(DRM_IOCTL_ARGS) 133 { 134 DRM_DEVICE; 135 int ret; 136 137 ret = drm_agp_do_release(dev); 138 return (ret); 139 } 140 141 /*ARGSUSED*/ 142 int 143 drm_agp_do_release(drm_softstate_t *dev) 144 { 145 int ret, rval; 146 147 if (!dev->agp) 148 return (ENODEV); 149 if (!dev->agp->acquired) 150 return (EBUSY); 151 152 if (dev->agpgart_hdl) { 153 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_RELEASE, 154 (intptr_t)0, FKIOCTL, kcred, &rval); 155 if (ret) { 156 DRM_ERROR("drm_agp_release: AGPIOC_RELEASE failed\n"); 157 (void) ldi_close(dev->agpgart_hdl, FEXCL, kcred); 158 dev->agpgart_hdl = NULL; 159 return (ENXIO); 160 } 161 } 162 (void) ldi_close(dev->agpgart_hdl, FEXCL, kcred); 163 dev->agpgart_hdl = NULL; 164 dev->agp->acquired = 0; 165 166 return (0); 167 } 168 169 /*ARGSUSED*/ 170 int 171 drm_agp_enable(DRM_IOCTL_ARGS) 172 { 173 DRM_DEVICE; 174 drm_agp_mode_t modes; 175 agp_setup_t setup; 176 int ret, rval; 177 178 if (!dev->agp) 179 return (ENODEV); 180 if (!dev->agp->acquired) 181 return (EBUSY); 182 183 DRM_COPY_FROM_USER_IOCTL(modes, (drm_agp_mode_t *)data, 184 sizeof (modes)); 185 186 dev->agp->mode = modes.mode; 187 setup.agps_mode = modes.mode; 188 189 DRM_DEBUG("drm_agp_enable: dev->agp->mode=%lx", modes.mode); 190 191 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_SETUP, 192 (intptr_t)&setup, FKIOCTL, 193 kcred, &rval); 194 if (ret) { 195 DRM_DEBUG("drm_agp_enable: failed"); 196 return (-1); 197 } 198 199 dev->agp->base = dev->agp->agp_info.agpi_aperbase; 200 dev->agp->enabled = 1; 201 202 DRM_DEBUG("drm_agp_enable: successful"); 203 return (0); 204 } 205 206 /*ARGSUSED*/ 207 int 208 drm_agp_alloc(DRM_IOCTL_ARGS) 209 { 210 DRM_DEVICE; 211 drm_agp_mem_t *entry; 212 agp_allocate_t alloc; 213 drm_agp_buffer_t request; 214 int pages; 215 int ret, rval; 216 217 if (!dev->agp || !dev->agp->acquired) 218 return (DRM_ERR(EINVAL)); 219 220 DRM_COPY_FROM_USER_IOCTL(request, 221 (drm_agp_buffer_t *)data, sizeof (request)); 222 223 if (!(entry = drm_calloc(1, sizeof (*entry), DRM_MEM_AGPLISTS))) 224 return (DRM_ERR(ENOMEM)); 225 226 alloc.agpa_type = _DRM_AGP_UMEM; 227 pages = btopr(request.size); 228 alloc.agpa_pgcount = pages; 229 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_ALLOCATE, 230 (intptr_t)&alloc, FKIOCTL, kcred, &rval); 231 if (ret) { 232 DRM_ERROR("drm_agp_alloc: AGPIOC_ALLOCATE failed"); 233 return (DDI_FAILURE); 234 } 235 236 entry->bound = 0; 237 entry->pages = pages; 238 entry->key = (unsigned int)alloc.agpa_key; 239 entry->prev = NULL; 240 entry->next = dev->agp->memory; 241 if (dev->agp->memory) 242 dev->agp->memory->prev = entry; 243 dev->agp->memory = entry; 244 245 request.handle = (unsigned long)entry->handle; 246 request.physical = alloc.agpa_physical; 247 DRM_DEBUG("drm_agp_alloc: virtual address is %lx physical is %lx\n", 248 entry->handle, 249 request.physical); 250 251 /* not used */ 252 /* dev->agp_umem_kvaddr = (unsigned long)alloc.agpa_kvaddr; */ 253 254 DRM_COPY_TO_USER_IOCTL((drm_agp_buffer_t *)data, 255 request, sizeof (request)); 256 257 return (0); 258 } 259 260 /*ARGSUSED*/ 261 static drm_agp_mem_t * 262 drm_agp_lookup_entry(drm_softstate_t *dev, void *handle) 263 { 264 drm_agp_mem_t *entry; 265 266 DRM_DEBUG("drm_agp_lookup_entry"); 267 for (entry = dev->agp->memory; entry; entry = entry->next) { 268 if (entry->handle == handle) 269 return (entry); 270 } 271 272 return (NULL); 273 } 274 275 /*ARGSUSED*/ 276 int 277 drm_agp_unbind(DRM_IOCTL_ARGS) 278 { 279 DRM_DEVICE; 280 agp_unbind_t unbind; 281 drm_agp_binding_t request; 282 drm_agp_mem_t *entry; 283 int ret, rval; 284 285 if (!dev->agp || !dev->agp->acquired) 286 return (DRM_ERR(EINVAL)); 287 DRM_COPY_FROM_USER_IOCTL(request, 288 (drm_agp_binding_t *)data, sizeof (request)); 289 290 if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle))) 291 return (DRM_ERR(EINVAL)); 292 if (!entry->bound) 293 return (DRM_ERR(EINVAL)); 294 295 unbind.agpu_pri = 0; 296 unbind.agpu_key = entry->key; 297 298 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_UNBIND, 299 (intptr_t)&unbind, FKIOCTL, kcred, &rval); 300 if (ret) { 301 DRM_ERROR("drm_agp_unbind: AGPIOC_UNBIND failed"); 302 return (-1); 303 } 304 entry->bound = 0; 305 return (0); 306 } 307 308 /*ARGSUSED*/ 309 int 310 drm_agp_bind(DRM_IOCTL_ARGS) 311 { 312 DRM_DEVICE; 313 drm_agp_binding_t request; 314 drm_agp_mem_t *entry; 315 int page; 316 317 if (!dev->agp || !dev->agp->acquired) 318 return (DRM_ERR(EINVAL)); 319 320 DRM_COPY_FROM_USER_IOCTL(request, 321 (drm_agp_binding_t *)data, sizeof (request)); 322 if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle))) 323 return (DRM_ERR(EINVAL)); 324 if (entry->bound) 325 return (DRM_ERR(EINVAL)); 326 327 page = btopr(request.offset); 328 if ((drm_agp_bind_memory(entry->key, page, dev)) < 0) 329 return (-1); 330 entry->bound = dev->agp->base + (page << AGP_PAGE_SHIFT); 331 332 DRM_DEBUG("drm_agp_bind: base = 0x%lx, entry->bound = 0x%lx", 333 dev->agp->base, entry->bound); 334 335 return (0); 336 } 337 338 /*ARGSUSED*/ 339 int 340 drm_agp_free(DRM_IOCTL_ARGS) 341 { 342 DRM_DEVICE; 343 drm_agp_buffer_t request; 344 drm_agp_mem_t *entry; 345 int ret, rval; 346 347 DRM_COPY_FROM_USER_IOCTL(request, (drm_agp_buffer_t *)data, 348 sizeof (request)); 349 if (!dev->agp || !dev->agp->acquired) 350 return (DRM_ERR(EINVAL)); 351 if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle))) 352 return (DRM_ERR(EINVAL)); 353 if (entry->bound) 354 (void) drm_agp_unbind_memory(request.handle, entry->key, dev); 355 356 if (entry->prev) 357 entry->prev->next = entry->next; 358 if (entry->next) 359 entry->next->prev = entry->prev; 360 361 drm_free(entry, sizeof (*entry), DRM_MEM_AGPLISTS); 362 entry = NULL; 363 364 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_DEALLOCATE, 365 (intptr_t)&(request.handle), FKIOCTL, kcred, &rval); 366 if (ret) { 367 DRM_ERROR("drm_agp_free: AGPIOC_DEALLOCATE failed"); 368 return (-1); 369 } 370 return (0); 371 } 372 373 /*ARGSUSED*/ 374 drm_agp_head_t * 375 drm_agp_init(void) 376 { 377 drm_agp_head_t *head = NULL; 378 379 DRM_DEBUG("drm_agp_init\n"); 380 if (!(head = drm_alloc(sizeof (drm_agp_head_t), DRM_MEM_AGPLISTS))) 381 return (NULL); 382 head->memory = NULL; 383 return (head); 384 error: 385 return (NULL); 386 } 387 388 /*ARGSUSED*/ 389 void 390 drm_agp_uninit(drm_agp_head_t *agp) 391 { 392 drm_free(agp, sizeof (drm_agp_head_t), DRM_MEM_AGPLISTS); 393 agp = NULL; 394 } 395 396 397 /*ARGSUSED*/ 398 void * 399 drm_agp_allocate_memory(size_t pages, uint32_t type) 400 { 401 return (NULL); 402 } 403 404 /*ARGSUSED*/ 405 int 406 drm_agp_free_memory(void *handle) 407 { 408 return (1); 409 } 410 411 /*ARGSUSED*/ 412 int 413 drm_agp_bind_memory(unsigned int key, uint32_t start, drm_device_t *dev) 414 { 415 agp_bind_t bind; 416 int ret, rval; 417 418 DRM_DEBUG("drm_agp_bind_memory"); 419 420 bind.agpb_pgstart = start; 421 bind.agpb_key = key; 422 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_BIND, 423 (intptr_t)&bind, FKIOCTL, kcred, &rval); 424 if (ret) { 425 DRM_DEBUG("drm_agp_bind_meory: AGPIOC_BIND failed"); 426 return (-1); 427 } 428 return (0); 429 } 430 431 /*ARGSUSED*/ 432 int 433 drm_agp_unbind_memory(unsigned long handle, uint32_t key, drm_device_t *dev) 434 { 435 agp_unbind_t unbind; 436 drm_agp_mem_t *entry; 437 int ret, rval; 438 439 if (!dev->agp || !dev->agp->acquired) 440 return (DRM_ERR(EINVAL)); 441 442 if (!(entry = drm_agp_lookup_entry(dev, (void *)handle))) 443 return (DRM_ERR(EINVAL)); 444 if (!entry->bound) 445 return (DRM_ERR(EINVAL)); 446 447 unbind.agpu_pri = 0; 448 unbind.agpu_key = entry->key; 449 450 ret = ldi_ioctl(dev->agpgart_hdl, AGPIOC_UNBIND, (intptr_t)&unbind, 451 FKIOCTL, kcred, &rval); 452 if (ret) { 453 DRM_ERROR("drm_agp_unbind: AGPIO_UNBIND failed"); 454 goto error; 455 } 456 entry->bound = 0; 457 return (0); 458 error: 459 return (-1); 460 } 461