1 /* 2 * Copyright 2009 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 * Copyright (c) 2009, Intel Corporation. 14 * All Rights Reserved. 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a 17 * copy of this software and associated documentation files (the "Software"), 18 * to deal in the Software without restriction, including without limitation 19 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 * and/or sell copies of the Software, and to permit persons to whom the 21 * Software is furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice (including the next 24 * paragraph) shall be included in all copies or substantial portions of the 25 * Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 * OTHER DEALINGS IN THE SOFTWARE. 34 * 35 * Author: 36 * Rickard E. (Rik) Faith <faith@valinux.com> 37 * Gareth Hughes <gareth@valinux.com> 38 * 39 */ 40 41 #include "drm.h" 42 #include "drmP.h" 43 44 #ifndef AGP_PAGE_SIZE 45 #define AGP_PAGE_SIZE 4096 46 #define AGP_PAGE_SHIFT 12 47 #endif 48 49 /* 50 * The agpa_key field of struct agp_allocate_t actually is 51 * an index to an array. It can be zero. But we will use 52 * this agpa_key as a handle returned to userland. Generally, 53 * 0 is not a valid value for a handle, so we add an offset 54 * to the key to get a handle. 55 */ 56 #define DRM_AGP_KEY_OFFSET 8 57 58 extern int drm_supp_device_capability(void *handle, int capid); 59 60 /*ARGSUSED*/ 61 int 62 drm_device_is_agp(drm_device_t *dev) 63 { 64 int ret; 65 66 if (dev->driver->device_is_agp != NULL) { 67 /* 68 * device_is_agp returns a tristate: 69 * 0 = not AGP; 70 * 1 = definitely AGP; 71 * 2 = fall back to PCI capability 72 */ 73 ret = (*dev->driver->device_is_agp)(dev); 74 if (ret != DRM_MIGHT_BE_AGP) 75 return (ret); 76 } 77 78 return (drm_supp_device_capability(dev->drm_handle, PCIY_AGP)); 79 80 } 81 82 /*ARGSUSED*/ 83 int 84 drm_device_is_pcie(drm_device_t *dev) 85 { 86 return (drm_supp_device_capability(dev->drm_handle, PCIY_EXPRESS)); 87 } 88 89 90 /*ARGSUSED*/ 91 int 92 drm_agp_info(DRM_IOCTL_ARGS) 93 { 94 DRM_DEVICE; 95 agp_info_t *agpinfo; 96 drm_agp_info_t info; 97 98 if (!dev->agp || !dev->agp->acquired) 99 return (EINVAL); 100 101 agpinfo = &dev->agp->agp_info; 102 info.agp_version_major = agpinfo->agpi_version.agpv_major; 103 info.agp_version_minor = agpinfo->agpi_version.agpv_minor; 104 info.mode = agpinfo->agpi_mode; 105 info.aperture_base = agpinfo->agpi_aperbase; 106 info.aperture_size = agpinfo->agpi_apersize* 1024 * 1024; 107 info.memory_allowed = agpinfo->agpi_pgtotal << PAGE_SHIFT; 108 info.memory_used = agpinfo->agpi_pgused << PAGE_SHIFT; 109 info.id_vendor = agpinfo->agpi_devid & 0xffff; 110 info.id_device = agpinfo->agpi_devid >> 16; 111 112 DRM_COPYTO_WITH_RETURN((void *)data, &info, sizeof (info)); 113 return (0); 114 } 115 116 /*ARGSUSED*/ 117 int 118 drm_agp_acquire(DRM_IOCTL_ARGS) 119 { 120 DRM_DEVICE; 121 int ret, rval; 122 123 if (!dev->agp) { 124 DRM_ERROR("drm_agp_acquire : agp isn't initialized yet"); 125 return (ENODEV); 126 } 127 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ACQUIRE, 128 (uintptr_t)0, FKIOCTL, kcred, &rval); 129 if (ret) { 130 DRM_ERROR("drm_agp_acquired: AGPIOC_ACQUIRE failed\n"); 131 return (EIO); 132 } 133 dev->agp->acquired = 1; 134 135 return (0); 136 } 137 138 /*ARGSUSED*/ 139 int 140 drm_agp_release(DRM_IOCTL_ARGS) 141 { 142 DRM_DEVICE; 143 int ret, rval; 144 145 if (!dev->agp) 146 return (ENODEV); 147 if (!dev->agp->acquired) 148 return (EBUSY); 149 150 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RELEASE, 151 (intptr_t)0, FKIOCTL, kcred, &rval); 152 if (ret) { 153 DRM_ERROR("drm_agp_release: AGPIOC_RELEASE failed\n"); 154 return (ENXIO); 155 } 156 dev->agp->acquired = 0; 157 158 return (ret); 159 } 160 161 162 int 163 drm_agp_do_release(drm_device_t *dev) 164 { 165 int ret, rval; 166 167 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_RELEASE, 168 (intptr_t)0, FKIOCTL, kcred, &rval); 169 170 if (ret == 0) 171 dev->agp->acquired = 0; 172 173 return (ret); 174 } 175 176 /*ARGSUSED*/ 177 int 178 drm_agp_enable(DRM_IOCTL_ARGS) 179 { 180 DRM_DEVICE; 181 drm_agp_mode_t modes; 182 agp_setup_t setup; 183 int ret, rval; 184 185 if (!dev->agp) 186 return (ENODEV); 187 if (!dev->agp->acquired) 188 return (EBUSY); 189 190 DRM_COPYFROM_WITH_RETURN(&modes, (void *)data, sizeof (modes)); 191 192 dev->agp->mode = modes.mode; 193 setup.agps_mode = (uint32_t)modes.mode; 194 195 196 DRM_DEBUG("drm_agp_enable: dev->agp->mode=%lx", modes.mode); 197 198 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_SETUP, 199 (intptr_t)&setup, FKIOCTL, kcred, &rval); 200 if (ret) { 201 DRM_ERROR("drm_agp_enable: failed"); 202 return (EIO); 203 } 204 205 dev->agp->base = dev->agp->agp_info.agpi_aperbase; 206 dev->agp->enabled = 1; 207 208 DRM_DEBUG("drm_agp_enable: dev->agp->base=0x%lx", dev->agp->base); 209 return (0); 210 } 211 212 /*ARGSUSED*/ 213 int 214 drm_agp_alloc(DRM_IOCTL_ARGS) 215 { 216 DRM_DEVICE; 217 drm_agp_mem_t *entry; 218 agp_allocate_t alloc; 219 drm_agp_buffer_t request; 220 int pages; 221 int ret, rval; 222 223 if (!dev->agp || !dev->agp->acquired) 224 return (EINVAL); 225 226 DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request)); 227 228 entry = kmem_zalloc(sizeof (*entry), KM_SLEEP); 229 230 pages = btopr(request.size); 231 alloc.agpa_pgcount = pages; 232 alloc.agpa_type = AGP_NORMAL; 233 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_ALLOCATE, 234 (intptr_t)&alloc, FKIOCTL, kcred, &rval); 235 if (ret) { 236 DRM_ERROR("drm_agp_alloc: AGPIOC_ALLOCATE failed, ret=%d", ret); 237 kmem_free(entry, sizeof (*entry)); 238 return (ret); 239 } 240 241 entry->bound = 0; 242 entry->pages = pages; 243 entry->handle = (void*)(uintptr_t)(alloc.agpa_key + DRM_AGP_KEY_OFFSET); 244 entry->prev = NULL; 245 entry->phys_addr = (void*)(uintptr_t)alloc.agpa_physical; 246 entry->next = dev->agp->memory; 247 if (dev->agp->memory) 248 dev->agp->memory->prev = entry; 249 dev->agp->memory = entry; 250 251 DRM_DEBUG("entry->phys_addr %lx", entry->phys_addr); 252 253 /* physical is used only by i810 driver */ 254 request.physical = alloc.agpa_physical; 255 request.handle = (unsigned long)entry->handle; 256 257 /* 258 * If failed to ddi_copyout(), we will free allocated AGP memory 259 * when closing drm 260 */ 261 DRM_COPYTO_WITH_RETURN((void *)data, &request, sizeof (request)); 262 263 return (0); 264 } 265 266 /*ARGSUSED*/ 267 static drm_agp_mem_t * 268 drm_agp_lookup_entry(drm_device_t *dev, void *handle) 269 { 270 drm_agp_mem_t *entry; 271 272 for (entry = dev->agp->memory; entry; entry = entry->next) { 273 if (entry->handle == handle) 274 return (entry); 275 } 276 277 return (NULL); 278 } 279 280 /*ARGSUSED*/ 281 int 282 drm_agp_unbind(DRM_IOCTL_ARGS) 283 { 284 DRM_DEVICE; 285 agp_unbind_t unbind; 286 drm_agp_binding_t request; 287 drm_agp_mem_t *entry; 288 int ret, rval; 289 290 if (!dev->agp || !dev->agp->acquired) 291 return (EINVAL); 292 293 DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request)); 294 295 if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle))) 296 return (EINVAL); 297 if (!entry->bound) 298 return (EINVAL); 299 300 unbind.agpu_pri = 0; 301 unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET; 302 303 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND, 304 (intptr_t)&unbind, FKIOCTL, kcred, &rval); 305 if (ret) { 306 DRM_ERROR("drm_agp_unbind: AGPIOC_UNBIND failed"); 307 return (EIO); 308 } 309 entry->bound = 0; 310 return (0); 311 } 312 313 /*ARGSUSED*/ 314 int 315 drm_agp_bind(DRM_IOCTL_ARGS) 316 { 317 DRM_DEVICE; 318 drm_agp_binding_t request; 319 drm_agp_mem_t *entry; 320 int start; 321 uint_t key; 322 323 if (!dev->agp || !dev->agp->acquired) 324 return (EINVAL); 325 326 DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request)); 327 328 entry = drm_agp_lookup_entry(dev, (void *)request.handle); 329 if (!entry || entry->bound) 330 return (EINVAL); 331 332 key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET; 333 start = btopr(request.offset); 334 if (drm_agp_bind_memory(key, start, dev)) { 335 DRM_ERROR("drm_agp_bind: failed key=%x, start=0x%x, " 336 "agp_base=0x%lx", key, start, dev->agp->base); 337 return (EIO); 338 } 339 340 entry->bound = dev->agp->base + (start << AGP_PAGE_SHIFT); 341 342 return (0); 343 } 344 345 /*ARGSUSED*/ 346 int 347 drm_agp_free(DRM_IOCTL_ARGS) 348 { 349 DRM_DEVICE; 350 drm_agp_buffer_t request; 351 drm_agp_mem_t *entry; 352 int ret, rval; 353 int agpu_key; 354 355 DRM_COPYFROM_WITH_RETURN(&request, (void *)data, sizeof (request)); 356 if (!dev->agp || !dev->agp->acquired) 357 return (EINVAL); 358 if (!(entry = drm_agp_lookup_entry(dev, (void *)request.handle))) 359 return (EINVAL); 360 if (entry->bound) 361 (void) drm_agp_unbind_memory(request.handle, dev); 362 363 if (entry == dev->agp->memory) 364 dev->agp->memory = entry->next; 365 if (entry->prev) 366 entry->prev->next = entry->next; 367 if (entry->next) 368 entry->next->prev = entry->prev; 369 370 agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET; 371 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_DEALLOCATE, 372 (intptr_t)agpu_key, FKIOCTL, kcred, &rval); 373 if (ret) { 374 DRM_ERROR("drm_agp_free: AGPIOC_DEALLOCATE failed," 375 "akey=%d, ret=%d", agpu_key, ret); 376 return (EIO); 377 } 378 drm_free(entry, sizeof (*entry), DRM_MEM_AGPLISTS); 379 return (0); 380 } 381 382 /*ARGSUSED*/ 383 drm_agp_head_t * 384 drm_agp_init(drm_device_t *dev) 385 { 386 drm_agp_head_t *agp = NULL; 387 int retval, rval; 388 389 agp = kmem_zalloc(sizeof (drm_agp_head_t), KM_SLEEP); 390 391 retval = ldi_ident_from_dip(dev->dip, &agp->agpgart_li); 392 if (retval != 0) { 393 DRM_ERROR("drm_agp_init: failed to get layerd ident, retval=%d", 394 retval); 395 goto err_1; 396 } 397 398 retval = ldi_open_by_name(AGP_DEVICE, FEXCL, kcred, 399 &agp->agpgart_lh, agp->agpgart_li); 400 if (retval != 0) { 401 DRM_ERROR("drm_agp_init: failed to open %s, retval=%d", 402 AGP_DEVICE, retval); 403 goto err_2; 404 } 405 406 retval = ldi_ioctl(agp->agpgart_lh, AGPIOC_INFO, 407 (intptr_t)&agp->agp_info, FKIOCTL, kcred, &rval); 408 409 if (retval != 0) { 410 DRM_ERROR("drm_agp_init: failed to get agpinfo, retval=%d", 411 retval); 412 goto err_3; 413 } 414 415 return (agp); 416 417 err_3: 418 (void) ldi_close(agp->agpgart_lh, FEXCL, kcred); 419 420 err_2: 421 ldi_ident_release(agp->agpgart_li); 422 423 err_1: 424 kmem_free(agp, sizeof (drm_agp_head_t)); 425 return (NULL); 426 } 427 428 /*ARGSUSED*/ 429 void 430 drm_agp_fini(drm_device_t *dev) 431 { 432 drm_agp_head_t *agp = dev->agp; 433 (void) ldi_close(agp->agpgart_lh, FEXCL, kcred); 434 ldi_ident_release(agp->agpgart_li); 435 kmem_free(agp, sizeof (drm_agp_head_t)); 436 dev->agp = NULL; 437 } 438 439 440 /*ARGSUSED*/ 441 void * 442 drm_agp_allocate_memory(size_t pages, uint32_t type, drm_device_t *dev) 443 { 444 return (NULL); 445 } 446 447 /*ARGSUSED*/ 448 int 449 drm_agp_free_memory(agp_allocate_t *handle, drm_device_t *dev) 450 { 451 return (1); 452 } 453 454 /*ARGSUSED*/ 455 int 456 drm_agp_bind_memory(unsigned int key, uint32_t start, drm_device_t *dev) 457 { 458 agp_bind_t bind; 459 int ret, rval; 460 461 bind.agpb_pgstart = start; 462 bind.agpb_key = key; 463 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_BIND, 464 (intptr_t)&bind, FKIOCTL, kcred, &rval); 465 if (ret) { 466 DRM_DEBUG("drm_agp_bind_meory: AGPIOC_BIND failed"); 467 return (EIO); 468 } 469 return (0); 470 } 471 472 /*ARGSUSED*/ 473 int 474 drm_agp_unbind_memory(unsigned long handle, drm_device_t *dev) 475 { 476 agp_unbind_t unbind; 477 drm_agp_mem_t *entry; 478 int ret, rval; 479 480 if (!dev->agp || !dev->agp->acquired) 481 return (EINVAL); 482 483 entry = drm_agp_lookup_entry(dev, (void *)handle); 484 if (!entry || !entry->bound) 485 return (EINVAL); 486 487 unbind.agpu_pri = 0; 488 unbind.agpu_key = (uintptr_t)entry->handle - DRM_AGP_KEY_OFFSET; 489 490 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_UNBIND, 491 (intptr_t)&unbind, FKIOCTL, kcred, &rval); 492 if (ret) { 493 DRM_ERROR("drm_agp_unbind: AGPIO_UNBIND failed"); 494 return (EIO); 495 } 496 entry->bound = 0; 497 return (0); 498 } 499 500 /* 501 * Binds a collection of pages into AGP memory at the given offset, returning 502 * the AGP memory structure containing them. 503 * 504 * No reference is held on the pages during this time -- it is up to the 505 * caller to handle that. 506 */ 507 int 508 drm_agp_bind_pages(drm_device_t *dev, 509 pfn_t *pages, 510 unsigned long num_pages, 511 uint32_t gtt_offset) 512 { 513 514 agp_bind_pages_t bind; 515 int ret, rval; 516 517 bind.agpb_pgstart = gtt_offset / AGP_PAGE_SIZE; 518 bind.agpb_pgcount = num_pages; 519 bind.agpb_pages = pages; 520 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_BIND, 521 (intptr_t)&bind, FKIOCTL, kcred, &rval); 522 if (ret) { 523 DRM_ERROR("AGPIOC_PAGES_BIND failed ret %d", ret); 524 return (ret); 525 } 526 return (0); 527 } 528 529 int 530 drm_agp_unbind_pages(drm_device_t *dev, 531 unsigned long num_pages, 532 uint32_t gtt_offset, 533 uint32_t type) 534 { 535 536 agp_unbind_pages_t unbind; 537 int ret, rval; 538 539 unbind.agpb_pgstart = gtt_offset / AGP_PAGE_SIZE; 540 unbind.agpb_pgcount = num_pages; 541 unbind.agpb_type = type; 542 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_UNBIND, 543 (intptr_t)&unbind, FKIOCTL, kcred, &rval); 544 if (ret) { 545 DRM_DEBUG("drm_agp_unbind_pages AGPIOC_PAGES_UNBIND failed"); 546 return (ret); 547 } 548 return (0); 549 } 550 551 /* 552 * Certain Intel chipsets contains a global write buffer, and this can require 553 * flushing from the drm or X.org to make sure all data has hit RAM before 554 * initiating a GPU transfer, due to a lack of coherency with the integrated 555 * graphics device and this buffer. 556 */ 557 void 558 drm_agp_chipset_flush(struct drm_device *dev) 559 { 560 int ret, rval; 561 562 DRM_DEBUG("agp_chipset_flush"); 563 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_FLUSHCHIPSET, 564 (intptr_t)0, FKIOCTL, kcred, &rval); 565 if (ret != 0) { 566 DRM_ERROR("Failed to drm_agp_chipset_flush ret %d", ret); 567 } 568 } 569 570 /* 571 * The pages are evict on suspend, so re-bind it at resume time 572 */ 573 void 574 drm_agp_rebind(struct drm_device *dev) 575 { 576 int ret, rval; 577 578 if (!dev->agp) { 579 return; 580 } 581 582 ret = ldi_ioctl(dev->agp->agpgart_lh, AGPIOC_PAGES_REBIND, 583 (intptr_t)0, FKIOCTL, kcred, &rval); 584 if (ret != 0) { 585 DRM_ERROR("rebind failed %d", ret); 586 } 587 }