1 /*- 2 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 3 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Rickard E. (Rik) Faith <faith@valinux.com> 27 * Gareth Hughes <gareth@valinux.com> 28 * 29 */ 30 31 /** @file drm_bufs.c 32 * Implementation of the ioctls for setup of DRM mappings and DMA buffers. 33 */ 34 35 #include "bus/pci/pcireg.h" 36 37 #include "dev/drm/drmP.h" 38 39 /* Allocation of PCI memory resources (framebuffer, registers, etc.) for 40 * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 41 * address for accessing them. Cleaned up at unload. 42 */ 43 static int drm_alloc_resource(struct drm_device *dev, int resource) 44 { 45 if (resource >= DRM_MAX_PCI_RESOURCE) { 46 DRM_ERROR("Resource %d too large\n", resource); 47 return 1; 48 } 49 50 DRM_UNLOCK(); 51 if (dev->pcir[resource] != NULL) { 52 DRM_LOCK(); 53 return 0; 54 } 55 56 dev->pcirid[resource] = PCIR_BAR(resource); 57 dev->pcir[resource] = bus_alloc_resource_any(dev->device, 58 SYS_RES_MEMORY, &dev->pcirid[resource], RF_SHAREABLE); 59 DRM_LOCK(); 60 61 if (dev->pcir[resource] == NULL) { 62 DRM_ERROR("Couldn't find resource 0x%x\n", resource); 63 return 1; 64 } 65 66 return 0; 67 } 68 69 unsigned long drm_get_resource_start(struct drm_device *dev, 70 unsigned int resource) 71 { 72 if (drm_alloc_resource(dev, resource) != 0) 73 return 0; 74 75 return rman_get_start(dev->pcir[resource]); 76 } 77 78 unsigned long drm_get_resource_len(struct drm_device *dev, 79 unsigned int resource) 80 { 81 if (drm_alloc_resource(dev, resource) != 0) 82 return 0; 83 84 return rman_get_size(dev->pcir[resource]); 85 } 86 87 int drm_addmap(struct drm_device * dev, unsigned long offset, 88 unsigned long size, 89 enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr) 90 { 91 drm_local_map_t *map; 92 int align; 93 /*drm_agp_mem_t *entry; 94 int valid;*/ 95 96 /* Only allow shared memory to be removable since we only keep enough 97 * book keeping information about shared memory to allow for removal 98 * when processes fork. 99 */ 100 if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 101 DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 102 return EINVAL; 103 } 104 if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 105 DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 106 offset, size); 107 return EINVAL; 108 } 109 if (offset + size < offset) { 110 DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 111 offset, size); 112 return EINVAL; 113 } 114 if (size == 0) { 115 DRM_ERROR("size is 0: 0x%lx/0x%lx\n", offset, size); 116 return EINVAL; 117 } 118 119 DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 120 size, type); 121 122 /* Check if this is just another version of a kernel-allocated map, and 123 * just hand that back if so. 124 */ 125 if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 126 type == _DRM_SHM) { 127 TAILQ_FOREACH(map, &dev->maplist, link) { 128 if (map->type == type && (map->offset == offset || 129 (map->type == _DRM_SHM && 130 map->flags == _DRM_CONTAINS_LOCK))) { 131 map->size = size; 132 DRM_DEBUG("Found kernel map %d\n", type); 133 goto done; 134 } 135 } 136 } 137 DRM_UNLOCK(); 138 139 /* Allocate a new map structure, fill it in, and do any type-specific 140 * initialization necessary. 141 */ 142 map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); 143 if (!map) { 144 DRM_LOCK(); 145 return ENOMEM; 146 } 147 148 map->offset = offset; 149 map->size = size; 150 map->type = type; 151 map->flags = flags; 152 153 switch (map->type) { 154 case _DRM_REGISTERS: 155 map->handle = drm_ioremap(dev, map); 156 if (!(map->flags & _DRM_WRITE_COMBINING)) 157 break; 158 /* FALLTHROUGH */ 159 case _DRM_FRAME_BUFFER: 160 if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 161 map->mtrr = 1; 162 break; 163 case _DRM_SHM: 164 map->handle = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT); 165 DRM_DEBUG("%lu %d %p\n", 166 map->size, drm_order(map->size), map->handle); 167 if (!map->handle) { 168 free(map, DRM_MEM_MAPS); 169 DRM_LOCK(); 170 return ENOMEM; 171 } 172 map->offset = (unsigned long)map->handle; 173 if (map->flags & _DRM_CONTAINS_LOCK) { 174 /* Prevent a 2nd X Server from creating a 2nd lock */ 175 DRM_LOCK(); 176 if (dev->lock.hw_lock != NULL) { 177 DRM_UNLOCK(); 178 free(map->handle, DRM_MEM_MAPS); 179 free(map, DRM_MEM_MAPS); 180 return EBUSY; 181 } 182 dev->lock.hw_lock = map->handle; /* Pointer to lock */ 183 DRM_UNLOCK(); 184 } 185 break; 186 case _DRM_AGP: 187 /*valid = 0;*/ 188 /* In some cases (i810 driver), user space may have already 189 * added the AGP base itself, because dev->agp->base previously 190 * only got set during AGP enable. So, only add the base 191 * address if the map's offset isn't already within the 192 * aperture. 193 */ 194 if (map->offset < dev->agp->base || 195 map->offset > dev->agp->base + 196 dev->agp->info.ai_aperture_size - 1) { 197 map->offset += dev->agp->base; 198 } 199 map->mtrr = dev->agp->mtrr; /* for getmap */ 200 /*for (entry = dev->agp->memory; entry; entry = entry->next) { 201 if ((map->offset >= entry->bound) && 202 (map->offset + map->size <= 203 entry->bound + entry->pages * PAGE_SIZE)) { 204 valid = 1; 205 break; 206 } 207 } 208 if (!valid) { 209 free(map, DRM_MEM_MAPS); 210 DRM_LOCK(); 211 return EACCES; 212 }*/ 213 break; 214 case _DRM_SCATTER_GATHER: 215 if (!dev->sg) { 216 free(map, DRM_MEM_MAPS); 217 DRM_LOCK(); 218 return EINVAL; 219 } 220 map->offset += dev->sg->handle; 221 break; 222 case _DRM_CONSISTENT: 223 /* Unfortunately, we don't get any alignment specification from 224 * the caller, so we have to guess. drm_pci_alloc requires 225 * a power-of-two alignment, so try to align the bus address of 226 * the map to it size if possible, otherwise just assume 227 * PAGE_SIZE alignment. 228 */ 229 align = map->size; 230 if ((align & (align - 1)) != 0) 231 align = PAGE_SIZE; 232 map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 233 if (map->dmah == NULL) { 234 free(map, DRM_MEM_MAPS); 235 DRM_LOCK(); 236 return ENOMEM; 237 } 238 map->handle = map->dmah->vaddr; 239 map->offset = map->dmah->busaddr; 240 break; 241 default: 242 DRM_ERROR("Bad map type %d\n", map->type); 243 free(map, DRM_MEM_MAPS); 244 DRM_LOCK(); 245 return EINVAL; 246 } 247 248 DRM_LOCK(); 249 TAILQ_INSERT_TAIL(&dev->maplist, map, link); 250 251 done: 252 /* Jumped to, with lock held, when a kernel map is found. */ 253 254 DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 255 map->size); 256 257 *map_ptr = map; 258 259 return 0; 260 } 261 262 int drm_addmap_ioctl(struct drm_device *dev, void *data, 263 struct drm_file *file_priv) 264 { 265 struct drm_map *request = data; 266 drm_local_map_t *map; 267 int err; 268 269 if (!(dev->flags & (FREAD|FWRITE))) 270 return EACCES; /* Require read/write */ 271 272 if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) 273 return EACCES; 274 275 DRM_LOCK(); 276 err = drm_addmap(dev, request->offset, request->size, request->type, 277 request->flags, &map); 278 DRM_UNLOCK(); 279 if (err != 0) 280 return err; 281 282 request->offset = map->offset; 283 request->size = map->size; 284 request->type = map->type; 285 request->flags = map->flags; 286 request->mtrr = map->mtrr; 287 request->handle = map->handle; 288 289 if (request->type != _DRM_SHM) { 290 request->handle = (void *)request->offset; 291 } 292 293 return 0; 294 } 295 296 void drm_rmmap(struct drm_device *dev, drm_local_map_t *map) 297 { 298 DRM_SPINLOCK_ASSERT(&dev->dev_lock); 299 300 if (map == NULL) 301 return; 302 303 TAILQ_REMOVE(&dev->maplist, map, link); 304 305 switch (map->type) { 306 case _DRM_REGISTERS: 307 if (map->bsr == NULL) 308 drm_ioremapfree(map); 309 /* FALLTHROUGH */ 310 case _DRM_FRAME_BUFFER: 311 if (map->mtrr) { 312 int __unused retcode; 313 314 retcode = drm_mtrr_del(0, map->offset, map->size, 315 DRM_MTRR_WC); 316 DRM_DEBUG("mtrr_del = %d\n", retcode); 317 } 318 break; 319 case _DRM_SHM: 320 free(map->handle, DRM_MEM_MAPS); 321 break; 322 case _DRM_AGP: 323 case _DRM_SCATTER_GATHER: 324 break; 325 case _DRM_CONSISTENT: 326 drm_pci_free(dev, map->dmah); 327 break; 328 default: 329 DRM_ERROR("Bad map type %d\n", map->type); 330 break; 331 } 332 333 if (map->bsr != NULL) { 334 bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 335 map->bsr); 336 } 337 338 free(map, DRM_MEM_MAPS); 339 } 340 341 /* Remove a map private from list and deallocate resources if the mapping 342 * isn't in use. 343 */ 344 345 int drm_rmmap_ioctl(struct drm_device *dev, void *data, 346 struct drm_file *file_priv) 347 { 348 drm_local_map_t *map; 349 struct drm_map *request = data; 350 351 DRM_LOCK(); 352 TAILQ_FOREACH(map, &dev->maplist, link) { 353 if (map->handle == request->handle && 354 map->flags & _DRM_REMOVABLE) 355 break; 356 } 357 358 /* No match found. */ 359 if (map == NULL) { 360 DRM_UNLOCK(); 361 return EINVAL; 362 } 363 364 drm_rmmap(dev, map); 365 366 DRM_UNLOCK(); 367 368 return 0; 369 } 370 371 372 static void drm_cleanup_buf_error(struct drm_device *dev, 373 drm_buf_entry_t *entry) 374 { 375 int i; 376 377 if (entry->seg_count) { 378 for (i = 0; i < entry->seg_count; i++) { 379 drm_pci_free(dev, entry->seglist[i]); 380 } 381 free(entry->seglist, DRM_MEM_SEGS); 382 383 entry->seg_count = 0; 384 } 385 386 if (entry->buf_count) { 387 for (i = 0; i < entry->buf_count; i++) { 388 free(entry->buflist[i].dev_private, DRM_MEM_BUFS); 389 } 390 free(entry->buflist, DRM_MEM_BUFS); 391 392 entry->buf_count = 0; 393 } 394 } 395 396 static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 397 { 398 drm_device_dma_t *dma = dev->dma; 399 drm_buf_entry_t *entry; 400 /*drm_agp_mem_t *agp_entry; 401 int valid*/ 402 drm_buf_t *buf; 403 unsigned long offset; 404 unsigned long agp_offset; 405 int count; 406 int order; 407 int size; 408 int alignment; 409 int page_order; 410 int total; 411 int byte_count; 412 int i; 413 drm_buf_t **temp_buflist; 414 415 count = request->count; 416 order = drm_order(request->size); 417 size = 1 << order; 418 419 alignment = (request->flags & _DRM_PAGE_ALIGN) 420 ? round_page(size) : size; 421 page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 422 total = PAGE_SIZE << page_order; 423 424 byte_count = 0; 425 agp_offset = dev->agp->base + request->agp_start; 426 427 DRM_DEBUG("count: %d\n", count); 428 DRM_DEBUG("order: %d\n", order); 429 DRM_DEBUG("size: %d\n", size); 430 DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset); 431 DRM_DEBUG("alignment: %d\n", alignment); 432 DRM_DEBUG("page_order: %d\n", page_order); 433 DRM_DEBUG("total: %d\n", total); 434 435 /* Make sure buffers are located in AGP memory that we own */ 436 /* Breaks MGA due to drm_alloc_agp not setting up entries for the 437 * memory. Safe to ignore for now because these ioctls are still 438 * root-only. 439 */ 440 /*valid = 0; 441 for (agp_entry = dev->agp->memory; agp_entry; 442 agp_entry = agp_entry->next) { 443 if ((agp_offset >= agp_entry->bound) && 444 (agp_offset + total * count <= 445 agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 446 valid = 1; 447 break; 448 } 449 } 450 if (!valid) { 451 DRM_DEBUG("zone invalid\n"); 452 return EINVAL; 453 }*/ 454 455 entry = &dma->bufs[order]; 456 457 entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 458 M_NOWAIT | M_ZERO); 459 if (!entry->buflist) { 460 return ENOMEM; 461 } 462 463 entry->buf_size = size; 464 entry->page_order = page_order; 465 466 offset = 0; 467 468 while (entry->buf_count < count) { 469 buf = &entry->buflist[entry->buf_count]; 470 buf->idx = dma->buf_count + entry->buf_count; 471 buf->total = alignment; 472 buf->order = order; 473 buf->used = 0; 474 475 buf->offset = (dma->byte_count + offset); 476 buf->bus_address = agp_offset + offset; 477 buf->address = (void *)(agp_offset + offset); 478 buf->next = NULL; 479 buf->pending = 0; 480 buf->file_priv = NULL; 481 482 buf->dev_priv_size = dev->driver->buf_priv_size; 483 buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 484 M_NOWAIT | M_ZERO); 485 if (buf->dev_private == NULL) { 486 /* Set count correctly so we free the proper amount. */ 487 entry->buf_count = count; 488 drm_cleanup_buf_error(dev, entry); 489 return ENOMEM; 490 } 491 492 offset += alignment; 493 entry->buf_count++; 494 byte_count += PAGE_SIZE << page_order; 495 } 496 497 DRM_DEBUG("byte_count: %d\n", byte_count); 498 499 temp_buflist = realloc(dma->buflist, 500 (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 501 DRM_MEM_BUFS, M_NOWAIT); 502 if (temp_buflist == NULL) { 503 /* Free the entry because it isn't valid */ 504 drm_cleanup_buf_error(dev, entry); 505 return ENOMEM; 506 } 507 dma->buflist = temp_buflist; 508 509 for (i = 0; i < entry->buf_count; i++) { 510 dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 511 } 512 513 dma->buf_count += entry->buf_count; 514 dma->byte_count += byte_count; 515 516 DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 517 DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 518 519 request->count = entry->buf_count; 520 request->size = size; 521 522 dma->flags = _DRM_DMA_USE_AGP; 523 524 return 0; 525 } 526 527 static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 528 { 529 drm_device_dma_t *dma = dev->dma; 530 int count; 531 int order; 532 int size; 533 int total; 534 int page_order; 535 drm_buf_entry_t *entry; 536 drm_buf_t *buf; 537 int alignment; 538 unsigned long offset; 539 int i; 540 int byte_count; 541 int page_count; 542 unsigned long *temp_pagelist; 543 drm_buf_t **temp_buflist; 544 545 count = request->count; 546 order = drm_order(request->size); 547 size = 1 << order; 548 549 DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", 550 request->count, request->size, size, order); 551 552 alignment = (request->flags & _DRM_PAGE_ALIGN) 553 ? round_page(size) : size; 554 page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 555 total = PAGE_SIZE << page_order; 556 557 entry = &dma->bufs[order]; 558 559 entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 560 M_NOWAIT | M_ZERO); 561 entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, 562 M_NOWAIT | M_ZERO); 563 564 /* Keep the original pagelist until we know all the allocations 565 * have succeeded 566 */ 567 temp_pagelist = malloc((dma->page_count + (count << page_order)) * 568 sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT); 569 570 if (entry->buflist == NULL || entry->seglist == NULL || 571 temp_pagelist == NULL) { 572 free(temp_pagelist, DRM_MEM_PAGES); 573 free(entry->seglist, DRM_MEM_SEGS); 574 free(entry->buflist, DRM_MEM_BUFS); 575 return ENOMEM; 576 } 577 578 memcpy(temp_pagelist, dma->pagelist, dma->page_count * 579 sizeof(*dma->pagelist)); 580 581 DRM_DEBUG("pagelist: %d entries\n", 582 dma->page_count + (count << page_order)); 583 584 entry->buf_size = size; 585 entry->page_order = page_order; 586 byte_count = 0; 587 page_count = 0; 588 589 while (entry->buf_count < count) { 590 DRM_SPINUNLOCK(&dev->dma_lock); 591 drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 592 0xfffffffful); 593 DRM_SPINLOCK(&dev->dma_lock); 594 if (dmah == NULL) { 595 /* Set count correctly so we free the proper amount. */ 596 entry->buf_count = count; 597 entry->seg_count = count; 598 drm_cleanup_buf_error(dev, entry); 599 free(temp_pagelist, DRM_MEM_PAGES); 600 return ENOMEM; 601 } 602 603 entry->seglist[entry->seg_count++] = dmah; 604 for (i = 0; i < (1 << page_order); i++) { 605 DRM_DEBUG("page %d @ %p\n", 606 dma->page_count + page_count, 607 (char *)dmah->vaddr + PAGE_SIZE * i); 608 temp_pagelist[dma->page_count + page_count++] = 609 (long)dmah->vaddr + PAGE_SIZE * i; 610 } 611 for (offset = 0; 612 offset + size <= total && entry->buf_count < count; 613 offset += alignment, ++entry->buf_count) { 614 buf = &entry->buflist[entry->buf_count]; 615 buf->idx = dma->buf_count + entry->buf_count; 616 buf->total = alignment; 617 buf->order = order; 618 buf->used = 0; 619 buf->offset = (dma->byte_count + byte_count + offset); 620 buf->address = ((char *)dmah->vaddr + offset); 621 buf->bus_address = dmah->busaddr + offset; 622 buf->next = NULL; 623 buf->pending = 0; 624 buf->file_priv = NULL; 625 626 buf->dev_priv_size = dev->driver->buf_priv_size; 627 buf->dev_private = malloc(buf->dev_priv_size, 628 DRM_MEM_BUFS, M_NOWAIT | M_ZERO); 629 if (buf->dev_private == NULL) { 630 /* Set count correctly so we free the proper amount. */ 631 entry->buf_count = count; 632 entry->seg_count = count; 633 drm_cleanup_buf_error(dev, entry); 634 free(temp_pagelist, DRM_MEM_PAGES); 635 return ENOMEM; 636 } 637 638 DRM_DEBUG("buffer %d @ %p\n", 639 entry->buf_count, buf->address); 640 } 641 byte_count += PAGE_SIZE << page_order; 642 } 643 644 temp_buflist = realloc(dma->buflist, 645 (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 646 DRM_MEM_BUFS, M_NOWAIT); 647 if (temp_buflist == NULL) { 648 /* Free the entry because it isn't valid */ 649 drm_cleanup_buf_error(dev, entry); 650 free(temp_pagelist, DRM_MEM_PAGES); 651 return ENOMEM; 652 } 653 dma->buflist = temp_buflist; 654 655 for (i = 0; i < entry->buf_count; i++) { 656 dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 657 } 658 659 /* No allocations failed, so now we can replace the orginal pagelist 660 * with the new one. 661 */ 662 free(dma->pagelist, DRM_MEM_PAGES); 663 dma->pagelist = temp_pagelist; 664 665 dma->buf_count += entry->buf_count; 666 dma->seg_count += entry->seg_count; 667 dma->page_count += entry->seg_count << page_order; 668 dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 669 670 request->count = entry->buf_count; 671 request->size = size; 672 673 return 0; 674 675 } 676 677 static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 678 { 679 drm_device_dma_t *dma = dev->dma; 680 drm_buf_entry_t *entry; 681 drm_buf_t *buf; 682 unsigned long offset; 683 unsigned long agp_offset; 684 int count; 685 int order; 686 int size; 687 int alignment; 688 int page_order; 689 int total; 690 int byte_count; 691 int i; 692 drm_buf_t **temp_buflist; 693 694 count = request->count; 695 order = drm_order(request->size); 696 size = 1 << order; 697 698 alignment = (request->flags & _DRM_PAGE_ALIGN) 699 ? round_page(size) : size; 700 page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 701 total = PAGE_SIZE << page_order; 702 703 byte_count = 0; 704 agp_offset = request->agp_start; 705 706 DRM_DEBUG("count: %d\n", count); 707 DRM_DEBUG("order: %d\n", order); 708 DRM_DEBUG("size: %d\n", size); 709 DRM_DEBUG("agp_offset: %ld\n", agp_offset); 710 DRM_DEBUG("alignment: %d\n", alignment); 711 DRM_DEBUG("page_order: %d\n", page_order); 712 DRM_DEBUG("total: %d\n", total); 713 714 entry = &dma->bufs[order]; 715 716 entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 717 M_NOWAIT | M_ZERO); 718 if (entry->buflist == NULL) 719 return ENOMEM; 720 721 entry->buf_size = size; 722 entry->page_order = page_order; 723 724 offset = 0; 725 726 while (entry->buf_count < count) { 727 buf = &entry->buflist[entry->buf_count]; 728 buf->idx = dma->buf_count + entry->buf_count; 729 buf->total = alignment; 730 buf->order = order; 731 buf->used = 0; 732 733 buf->offset = (dma->byte_count + offset); 734 buf->bus_address = agp_offset + offset; 735 buf->address = (void *)(agp_offset + offset + dev->sg->handle); 736 buf->next = NULL; 737 buf->pending = 0; 738 buf->file_priv = NULL; 739 740 buf->dev_priv_size = dev->driver->buf_priv_size; 741 buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 742 M_NOWAIT | M_ZERO); 743 if (buf->dev_private == NULL) { 744 /* Set count correctly so we free the proper amount. */ 745 entry->buf_count = count; 746 drm_cleanup_buf_error(dev, entry); 747 return ENOMEM; 748 } 749 750 DRM_DEBUG("buffer %d @ %p\n", 751 entry->buf_count, buf->address); 752 753 offset += alignment; 754 entry->buf_count++; 755 byte_count += PAGE_SIZE << page_order; 756 } 757 758 DRM_DEBUG("byte_count: %d\n", byte_count); 759 760 temp_buflist = realloc(dma->buflist, 761 (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 762 DRM_MEM_BUFS, M_NOWAIT); 763 if (temp_buflist == NULL) { 764 /* Free the entry because it isn't valid */ 765 drm_cleanup_buf_error(dev, entry); 766 return ENOMEM; 767 } 768 dma->buflist = temp_buflist; 769 770 for (i = 0; i < entry->buf_count; i++) { 771 dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 772 } 773 774 dma->buf_count += entry->buf_count; 775 dma->byte_count += byte_count; 776 777 DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 778 DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 779 780 request->count = entry->buf_count; 781 request->size = size; 782 783 dma->flags = _DRM_DMA_USE_SG; 784 785 return 0; 786 } 787 788 int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 789 { 790 int order, ret; 791 792 if (request->count < 0 || request->count > 4096) 793 return EINVAL; 794 795 order = drm_order(request->size); 796 if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 797 return EINVAL; 798 799 DRM_SPINLOCK(&dev->dma_lock); 800 801 /* No more allocations after first buffer-using ioctl. */ 802 if (dev->buf_use != 0) { 803 DRM_SPINUNLOCK(&dev->dma_lock); 804 return EBUSY; 805 } 806 /* No more than one allocation per order */ 807 if (dev->dma->bufs[order].buf_count != 0) { 808 DRM_SPINUNLOCK(&dev->dma_lock); 809 return ENOMEM; 810 } 811 812 ret = drm_do_addbufs_agp(dev, request); 813 814 DRM_SPINUNLOCK(&dev->dma_lock); 815 816 return ret; 817 } 818 819 int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 820 { 821 int order, ret; 822 823 if (!DRM_SUSER(DRM_CURPROC)) 824 return EACCES; 825 826 if (request->count < 0 || request->count > 4096) 827 return EINVAL; 828 829 order = drm_order(request->size); 830 if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 831 return EINVAL; 832 833 DRM_SPINLOCK(&dev->dma_lock); 834 835 /* No more allocations after first buffer-using ioctl. */ 836 if (dev->buf_use != 0) { 837 DRM_SPINUNLOCK(&dev->dma_lock); 838 return EBUSY; 839 } 840 /* No more than one allocation per order */ 841 if (dev->dma->bufs[order].buf_count != 0) { 842 DRM_SPINUNLOCK(&dev->dma_lock); 843 return ENOMEM; 844 } 845 846 ret = drm_do_addbufs_sg(dev, request); 847 848 DRM_SPINUNLOCK(&dev->dma_lock); 849 850 return ret; 851 } 852 853 int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 854 { 855 int order, ret; 856 857 if (!DRM_SUSER(DRM_CURPROC)) 858 return EACCES; 859 860 if (request->count < 0 || request->count > 4096) 861 return EINVAL; 862 863 order = drm_order(request->size); 864 if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 865 return EINVAL; 866 867 DRM_SPINLOCK(&dev->dma_lock); 868 869 /* No more allocations after first buffer-using ioctl. */ 870 if (dev->buf_use != 0) { 871 DRM_SPINUNLOCK(&dev->dma_lock); 872 return EBUSY; 873 } 874 /* No more than one allocation per order */ 875 if (dev->dma->bufs[order].buf_count != 0) { 876 DRM_SPINUNLOCK(&dev->dma_lock); 877 return ENOMEM; 878 } 879 880 ret = drm_do_addbufs_pci(dev, request); 881 882 DRM_SPINUNLOCK(&dev->dma_lock); 883 884 return ret; 885 } 886 887 int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 888 { 889 struct drm_buf_desc *request = data; 890 int err; 891 892 if (request->flags & _DRM_AGP_BUFFER) 893 err = drm_addbufs_agp(dev, request); 894 else if (request->flags & _DRM_SG_BUFFER) 895 err = drm_addbufs_sg(dev, request); 896 else 897 err = drm_addbufs_pci(dev, request); 898 899 return err; 900 } 901 902 int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 903 { 904 drm_device_dma_t *dma = dev->dma; 905 struct drm_buf_info *request = data; 906 int i; 907 int count; 908 int retcode = 0; 909 910 DRM_SPINLOCK(&dev->dma_lock); 911 ++dev->buf_use; /* Can't allocate more after this call */ 912 DRM_SPINUNLOCK(&dev->dma_lock); 913 914 for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 915 if (dma->bufs[i].buf_count) 916 ++count; 917 } 918 919 DRM_DEBUG("count = %d\n", count); 920 921 if (request->count >= count) { 922 for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 923 if (dma->bufs[i].buf_count) { 924 struct drm_buf_desc from; 925 926 from.count = dma->bufs[i].buf_count; 927 from.size = dma->bufs[i].buf_size; 928 from.low_mark = dma->bufs[i].freelist.low_mark; 929 from.high_mark = dma->bufs[i].freelist.high_mark; 930 931 if (DRM_COPY_TO_USER(&request->list[count], &from, 932 sizeof(struct drm_buf_desc)) != 0) { 933 retcode = EFAULT; 934 break; 935 } 936 937 DRM_DEBUG("%d %d %d %d %d\n", 938 i, dma->bufs[i].buf_count, 939 dma->bufs[i].buf_size, 940 dma->bufs[i].freelist.low_mark, 941 dma->bufs[i].freelist.high_mark); 942 ++count; 943 } 944 } 945 } 946 request->count = count; 947 948 return retcode; 949 } 950 951 int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 952 { 953 drm_device_dma_t *dma = dev->dma; 954 struct drm_buf_desc *request = data; 955 int order; 956 957 DRM_DEBUG("%d, %d, %d\n", 958 request->size, request->low_mark, request->high_mark); 959 960 961 order = drm_order(request->size); 962 if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 963 request->low_mark < 0 || request->high_mark < 0) { 964 return EINVAL; 965 } 966 967 DRM_SPINLOCK(&dev->dma_lock); 968 if (request->low_mark > dma->bufs[order].buf_count || 969 request->high_mark > dma->bufs[order].buf_count) { 970 DRM_SPINUNLOCK(&dev->dma_lock); 971 return EINVAL; 972 } 973 974 dma->bufs[order].freelist.low_mark = request->low_mark; 975 dma->bufs[order].freelist.high_mark = request->high_mark; 976 DRM_SPINUNLOCK(&dev->dma_lock); 977 978 return 0; 979 } 980 981 int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 982 { 983 drm_device_dma_t *dma = dev->dma; 984 struct drm_buf_free *request = data; 985 int i; 986 int idx; 987 drm_buf_t *buf; 988 int retcode = 0; 989 990 DRM_DEBUG("%d\n", request->count); 991 992 DRM_SPINLOCK(&dev->dma_lock); 993 for (i = 0; i < request->count; i++) { 994 if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { 995 retcode = EFAULT; 996 break; 997 } 998 if (idx < 0 || idx >= dma->buf_count) { 999 DRM_ERROR("Index %d (of %d max)\n", 1000 idx, dma->buf_count - 1); 1001 retcode = EINVAL; 1002 break; 1003 } 1004 buf = dma->buflist[idx]; 1005 if (buf->file_priv != file_priv) { 1006 DRM_ERROR("Process %d freeing buffer not owned\n", 1007 DRM_CURRENTPID); 1008 retcode = EINVAL; 1009 break; 1010 } 1011 drm_free_buffer(dev, buf); 1012 } 1013 DRM_SPINUNLOCK(&dev->dma_lock); 1014 1015 return retcode; 1016 } 1017 1018 int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 1019 { 1020 drm_device_dma_t *dma = dev->dma; 1021 int retcode = 0; 1022 const int zero = 0; 1023 vm_offset_t address; 1024 struct vmspace *vms; 1025 vm_ooffset_t foff; 1026 vm_size_t size; 1027 vm_offset_t vaddr; 1028 struct drm_buf_map *request = data; 1029 int i; 1030 1031 vms = DRM_CURPROC->td_proc->p_vmspace; 1032 1033 DRM_SPINLOCK(&dev->dma_lock); 1034 dev->buf_use++; /* Can't allocate more after this call */ 1035 DRM_SPINUNLOCK(&dev->dma_lock); 1036 1037 if (request->count < dma->buf_count) 1038 goto done; 1039 1040 if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || 1041 (drm_core_check_feature(dev, DRIVER_SG) && 1042 (dma->flags & _DRM_DMA_USE_SG))) { 1043 drm_local_map_t *map = dev->agp_buffer_map; 1044 1045 if (map == NULL) { 1046 retcode = EINVAL; 1047 goto done; 1048 } 1049 size = round_page(map->size); 1050 foff = map->offset; 1051 } else { 1052 size = round_page(dma->byte_count), 1053 foff = 0; 1054 } 1055 1056 vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1057 #if __FreeBSD_version >= 600023 1058 retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1059 VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, 1060 dev->devnode, foff); 1061 #else 1062 retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1063 VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, 1064 SLIST_FIRST(&dev->devnode->si_hlist), foff); 1065 #endif 1066 if (retcode) 1067 goto done; 1068 1069 request->virtual = (void *)vaddr; 1070 1071 for (i = 0; i < dma->buf_count; i++) { 1072 if (DRM_COPY_TO_USER(&request->list[i].idx, 1073 &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 1074 retcode = EFAULT; 1075 goto done; 1076 } 1077 if (DRM_COPY_TO_USER(&request->list[i].total, 1078 &dma->buflist[i]->total, sizeof(request->list[0].total))) { 1079 retcode = EFAULT; 1080 goto done; 1081 } 1082 if (DRM_COPY_TO_USER(&request->list[i].used, &zero, 1083 sizeof(zero))) { 1084 retcode = EFAULT; 1085 goto done; 1086 } 1087 address = vaddr + dma->buflist[i]->offset; /* *** */ 1088 if (DRM_COPY_TO_USER(&request->list[i].address, &address, 1089 sizeof(address))) { 1090 retcode = EFAULT; 1091 goto done; 1092 } 1093 } 1094 1095 done: 1096 request->count = dma->buf_count; 1097 1098 DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); 1099 1100 return retcode; 1101 } 1102 1103 /* 1104 * Compute order. Can be made faster. 1105 */ 1106 int drm_order(unsigned long size) 1107 { 1108 int order; 1109 1110 if (size == 0) 1111 return 0; 1112 1113 order = flsl(size) - 1; 1114 if (size & ~(1ul << order)) 1115 ++order; 1116 1117 return order; 1118 } 1119