1 /*
   2  * drm_bufs.h -- Generic buffer template -*- linux-c -*-
   3  * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
   4  */
   5 /*
   6  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
   7  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   8  * Copyright (c) 2009, Intel Corporation.
   9  * 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  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  28  * OTHER DEALINGS IN THE SOFTWARE.
  29  *
  30  * Authors:
  31  *    Rickard E. (Rik) Faith <faith@valinux.com>
  32  *    Gareth Hughes <gareth@valinux.com>
  33  *
  34  */
  35 
  36 /*
  37  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  38  * Use is subject to license terms.
  39  */
  40 
  41 #include "drmP.h"
  42 #include <sys/gfx_private.h>
  43 #include "drm_io32.h"
  44 
  45 
  46 #define PAGE_MASK       (PAGE_SIZE-1)
  47 #define round_page(x)   (((x) + PAGE_MASK) & ~PAGE_MASK)
  48 
  49 /*
  50  * Compute order.  Can be made faster.
  51  */
  52 int
  53 drm_order(unsigned long size)
  54 {
  55         int order = 0;
  56         unsigned long tmp = size;
  57 
  58         while (tmp >>= 1)
  59                 order ++;
  60 
  61         if (size & ~(1 << order))
  62                 ++order;
  63 
  64         return (order);
  65 }
  66 
  67 static inline drm_local_map_t *
  68 drm_find_map(drm_device_t *dev, u_offset_t offset, int type)
  69 {
  70         drm_local_map_t         *map;
  71 
  72         TAILQ_FOREACH(map, &dev->maplist, link) {
  73                 if ((map->type == type) && ((map->offset == offset) ||
  74                     (map->flags == _DRM_CONTAINS_LOCK) &&
  75                     (map->type == _DRM_SHM)))
  76                         return (map);
  77         }
  78 
  79         return (NULL);
  80 }
  81 
  82 int drm_addmap(drm_device_t *dev, unsigned long offset,
  83     unsigned long size, drm_map_type_t type,
  84     drm_map_flags_t flags, drm_local_map_t **map_ptr)
  85 {
  86         drm_local_map_t *map;
  87         caddr_t         kva;
  88         int             retval;
  89 
  90         /*
  91          * Only allow shared memory to be removable since we only keep
  92          * enough book keeping information about shared memory to allow
  93          * for removal when processes fork.
  94          */
  95         if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM)
  96                 return (EINVAL);
  97         if ((offset & PAGE_MASK) || (size & PAGE_MASK))
  98                 return (EINVAL);
  99         if (offset + size < offset)
 100                 return (EINVAL);
 101 
 102         /*
 103          * Check if this is just another version of a kernel-allocated
 104          * map, and just hand that back if so.
 105          */
 106         map = drm_find_map(dev, offset, type);
 107         if (map != NULL) {
 108                 goto done;
 109         }
 110 
 111         /*
 112          * Allocate a new map structure, fill it in, and do any
 113          * type-specific initialization necessary.
 114          */
 115         map = drm_alloc(sizeof (*map), DRM_MEM_MAPS);
 116         if (!map)
 117                 return (ENOMEM);
 118 
 119         map->offset = offset;
 120         map->size = size;
 121         map->type = type;
 122         map->flags = flags;
 123 
 124         switch (map->type) {
 125         case _DRM_REGISTERS:
 126         case _DRM_FRAME_BUFFER:
 127                 retval = drm_ioremap(dev, map);
 128                 if (retval)
 129                         return (retval);
 130                 break;
 131 
 132         case _DRM_SHM:
 133                 /*
 134                  * ddi_umem_alloc() grants page-aligned memory. We needn't
 135                  * handle alignment issue here.
 136                  */
 137                 map->handle = ddi_umem_alloc(map->size,
 138                     DDI_UMEM_NOSLEEP, &map->drm_umem_cookie);
 139                 if (!map->handle) {
 140                         DRM_ERROR("drm_addmap: ddi_umem_alloc failed");
 141                         drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 142                         return (ENOMEM);
 143                 }
 144                 /*
 145                  * record only low 32-bit of this handle, since 32-bit
 146                  * user app is incapable of passing in 64bit offset when
 147                  * doing mmap.
 148                  */
 149                 map->offset = (uintptr_t)map->handle;
 150                 map->offset &= 0xffffffffUL;
 151                 if (map->flags & _DRM_CONTAINS_LOCK) {
 152                         /* Prevent a 2nd X Server from creating a 2nd lock */
 153                         if (dev->lock.hw_lock != NULL) {
 154                                 ddi_umem_free(map->drm_umem_cookie);
 155                                 drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 156                                 return (EBUSY);
 157                         }
 158                         dev->lock.hw_lock = map->handle; /* Pointer to lock */
 159                 }
 160                 map->dev_addr = map->handle;
 161                 break;
 162         case _DRM_SCATTER_GATHER:
 163                 if (!dev->sg) {
 164                         drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 165                         return (EINVAL);
 166                 }
 167                 map->offset += (uintptr_t)dev->sg->virtual;
 168                 map->handle = (void *)(uintptr_t)map->offset;
 169                 map->dev_addr = dev->sg->virtual;
 170                 map->dev_handle = dev->sg->dmah_sg->acc_hdl;
 171                 break;
 172 
 173         case _DRM_CONSISTENT:
 174                 DRM_ERROR("%d DRM_AGP_CONSISTENT", __LINE__);
 175                 return (ENOTSUP);
 176         case _DRM_AGP:
 177                 map->offset += dev->agp->base;
 178                 kva = gfxp_map_kernel_space(map->offset, map->size,
 179                     GFXP_MEMORY_WRITECOMBINED);
 180                 if (kva == 0) {
 181                         drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 182                         cmn_err(CE_WARN,
 183                             "drm_addmap: failed to map AGP aperture");
 184                         return (ENOMEM);
 185                 }
 186                 map->handle = (void *)(uintptr_t)kva;
 187                 map->dev_addr = kva;
 188                 break;
 189         default:
 190                 drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 191                 return (EINVAL);
 192         }
 193 
 194         TAILQ_INSERT_TAIL(&dev->maplist, map, link);
 195 
 196 done:
 197         /* Jumped to, with lock held, when a kernel map is found. */
 198         *map_ptr = map;
 199 
 200         return (0);
 201 }
 202 
 203 /*ARGSUSED*/
 204 int
 205 drm_addmap_ioctl(DRM_IOCTL_ARGS)
 206 {
 207         drm_map_t request;
 208         drm_local_map_t *map;
 209         int err;
 210         DRM_DEVICE;
 211 
 212 #ifdef  _MULTI_DATAMODEL
 213         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 214                 drm_map_32_t request32;
 215                 DRM_COPYFROM_WITH_RETURN(&request32,
 216                     (void *)data, sizeof (request32));
 217                 request.offset = request32.offset;
 218                 request.size = request32.size;
 219                 request.type = request32.type;
 220                 request.flags = request32.flags;
 221                 request.mtrr = request32.mtrr;
 222         } else
 223 #endif
 224                 DRM_COPYFROM_WITH_RETURN(&request,
 225                     (void *)data, sizeof (request));
 226 
 227         err = drm_addmap(dev, request.offset, request.size, request.type,
 228             request.flags, &map);
 229 
 230         if (err != 0)
 231                 return (err);
 232 
 233         request.offset = map->offset;
 234         request.size = map->size;
 235         request.type = map->type;
 236         request.flags = map->flags;
 237         request.mtrr   = map->mtrr;
 238         request.handle = (uintptr_t)map->handle;
 239 
 240 #ifdef  _MULTI_DATAMODEL
 241         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 242                 drm_map_32_t request32;
 243                 request32.offset = request.offset;
 244                 request32.size = (uint32_t)request.size;
 245                 request32.type = request.type;
 246                 request32.flags = request.flags;
 247                 request32.handle = request.handle;
 248                 request32.mtrr = request.mtrr;
 249                 DRM_COPYTO_WITH_RETURN((void *)data,
 250                     &request32, sizeof (request32));
 251         } else
 252 #endif
 253                 DRM_COPYTO_WITH_RETURN((void *)data,
 254                     &request, sizeof (request));
 255 
 256         return (0);
 257 }
 258 
 259 void
 260 drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
 261 {
 262         DRM_SPINLOCK_ASSERT(&dev->dev_lock);
 263 
 264         TAILQ_REMOVE(&dev->maplist, map, link);
 265 
 266         switch (map->type) {
 267         case _DRM_REGISTERS:
 268                 drm_ioremapfree(map);
 269                 break;
 270                 /* FALLTHROUGH */
 271         case _DRM_FRAME_BUFFER:
 272                 drm_ioremapfree(map);
 273                 break;
 274         case _DRM_SHM:
 275                 ddi_umem_free(map->drm_umem_cookie);
 276                 break;
 277         case _DRM_AGP:
 278                 /*
 279                  * we mapped AGP aperture into kernel space in drm_addmap,
 280                  * here, unmap them and release kernel virtual address space
 281                  */
 282                 gfxp_unmap_kernel_space(map->dev_addr, map->size);
 283                 break;
 284 
 285         case _DRM_SCATTER_GATHER:
 286                 break;
 287         case _DRM_CONSISTENT:
 288                 break;
 289         default:
 290                 break;
 291         }
 292 
 293         drm_free(map, sizeof (*map), DRM_MEM_MAPS);
 294 }
 295 
 296 /*
 297  * Remove a map private from list and deallocate resources if the
 298  * mapping isn't in use.
 299  */
 300 /*ARGSUSED*/
 301 int
 302 drm_rmmap_ioctl(DRM_IOCTL_ARGS)
 303 {
 304         DRM_DEVICE;
 305         drm_local_map_t *map;
 306         drm_map_t request;
 307 
 308 #ifdef  _MULTI_DATAMODEL
 309         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 310                 drm_map_32_t request32;
 311                 DRM_COPYFROM_WITH_RETURN(&request32,
 312                     (void *)data, sizeof (drm_map_32_t));
 313                 request.offset = request32.offset;
 314                 request.size = request32.size;
 315                 request.type = request32.type;
 316                 request.flags = request32.flags;
 317                 request.handle = request32.handle;
 318                 request.mtrr = request32.mtrr;
 319         } else
 320 #endif
 321                 DRM_COPYFROM_WITH_RETURN(&request,
 322                     (void *)data, sizeof (request));
 323 
 324         DRM_LOCK();
 325         TAILQ_FOREACH(map, &dev->maplist, link) {
 326         if (((uintptr_t)map->handle == (request.handle & 0xffffffff)) &&
 327             (map->flags & _DRM_REMOVABLE))
 328                         break;
 329         }
 330 
 331         /* No match found. */
 332         if (map == NULL) {
 333                 DRM_UNLOCK();
 334                 return (EINVAL);
 335         }
 336 
 337         drm_rmmap(dev, map);
 338         DRM_UNLOCK();
 339 
 340         return (0);
 341 }
 342 
 343 /*ARGSUSED*/
 344 static void
 345 drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
 346 {
 347         int i;
 348 
 349         if (entry->seg_count) {
 350                 for (i = 0; i < entry->seg_count; i++) {
 351                         if (entry->seglist[i]) {
 352                                 DRM_ERROR(
 353                                     "drm_cleanup_buf_error: not implemented");
 354                         }
 355                 }
 356                 drm_free(entry->seglist,
 357                     entry->seg_count *
 358                     sizeof (*entry->seglist), DRM_MEM_SEGS);
 359                 entry->seg_count = 0;
 360         }
 361 
 362         if (entry->buf_count) {
 363                 for (i = 0; i < entry->buf_count; i++) {
 364                         if (entry->buflist[i].dev_private) {
 365                                 drm_free(entry->buflist[i].dev_private,
 366                                     entry->buflist[i].dev_priv_size,
 367                                     DRM_MEM_BUFS);
 368                         }
 369                 }
 370                 drm_free(entry->buflist,
 371                     entry->buf_count *
 372                     sizeof (*entry->buflist), DRM_MEM_BUFS);
 373                 entry->buflist = NULL;
 374                 entry->buf_count = 0;
 375         }
 376 }
 377 
 378 /*ARGSUSED*/
 379 int
 380 drm_markbufs(DRM_IOCTL_ARGS)
 381 {
 382         DRM_DEBUG("drm_markbufs");
 383         return (EINVAL);
 384 }
 385 
 386 /*ARGSUSED*/
 387 int
 388 drm_infobufs(DRM_IOCTL_ARGS)
 389 {
 390         DRM_DEBUG("drm_infobufs");
 391         return (EINVAL);
 392 }
 393 
 394 static int
 395 drm_do_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
 396 {
 397         drm_device_dma_t *dma = dev->dma;
 398         drm_buf_entry_t *entry;
 399         drm_buf_t **temp_buflist;
 400         drm_buf_t *buf;
 401         unsigned long offset;
 402         unsigned long agp_offset;
 403         int count;
 404         int order;
 405         int size;
 406         int alignment;
 407         int page_order;
 408         int byte_count;
 409         int i;
 410 
 411         if (!dma)
 412                 return (EINVAL);
 413 
 414         count = request->count;
 415         order = drm_order(request->size);
 416         size = 1 << order;
 417 
 418         alignment  = (request->flags & _DRM_PAGE_ALIGN)
 419             ? round_page(size) : size;
 420         page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
 421 
 422         byte_count = 0;
 423         agp_offset = dev->agp->base + request->agp_start;
 424 
 425         entry = &dma->bufs[order];
 426 
 427         /* No more than one allocation per order */
 428         if (entry->buf_count) {
 429                 return (ENOMEM);
 430         }
 431 
 432         entry->buflist = drm_alloc(count * sizeof (*entry->buflist),
 433             DRM_MEM_BUFS);
 434         if (!entry->buflist) {
 435                 return (ENOMEM);
 436         }
 437         entry->buf_size = size;
 438         entry->page_order = page_order;
 439 
 440         offset = 0;
 441 
 442         while (entry->buf_count < count) {
 443                 buf             = &entry->buflist[entry->buf_count];
 444                 buf->idx     = dma->buf_count + entry->buf_count;
 445                 buf->total   = alignment;
 446                 buf->order   = order;
 447                 buf->used    = 0;
 448 
 449                 buf->offset  = (dma->byte_count + offset);
 450                 buf->bus_address = agp_offset + offset;
 451                 buf->address = (void *)(agp_offset + offset);
 452                 buf->next    = NULL;
 453                 buf->pending = 0;
 454                 buf->filp    = NULL;
 455 
 456                 buf->dev_priv_size = dev->driver->buf_priv_size;
 457                 buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
 458                 if (buf->dev_private == NULL) {
 459                         /* Set count correctly so we free the proper amount. */
 460                         entry->buf_count = count;
 461                         drm_cleanup_buf_error(dev, entry);
 462                         return (ENOMEM);
 463                 }
 464 
 465                 offset += alignment;
 466                 entry->buf_count++;
 467                 byte_count += PAGE_SIZE << page_order;
 468         }
 469 
 470         temp_buflist = drm_alloc(
 471             (dma->buf_count + entry->buf_count) * sizeof (*dma->buflist),
 472             DRM_MEM_BUFS);
 473 
 474         if (temp_buflist == NULL) {
 475                 /* Free the entry because it isn't valid */
 476                 drm_cleanup_buf_error(dev, entry);
 477                 DRM_ERROR(" temp_buflist is NULL");
 478                 return (ENOMEM);
 479         }
 480 
 481         bcopy(temp_buflist, dma->buflist,
 482             dma->buf_count * sizeof (*dma->buflist));
 483         kmem_free(dma->buflist, dma->buf_count *sizeof (*dma->buflist));
 484         dma->buflist = temp_buflist;
 485 
 486         for (i = 0; i < entry->buf_count; i++) {
 487                 dma->buflist[i + dma->buf_count] = &entry->buflist[i];
 488         }
 489 
 490         dma->buf_count += entry->buf_count;
 491         dma->byte_count += byte_count;
 492         dma->seg_count += entry->seg_count;
 493         dma->page_count += byte_count >> PAGE_SHIFT;
 494 
 495         request->count = entry->buf_count;
 496         request->size = size;
 497 
 498         dma->flags = _DRM_DMA_USE_AGP;
 499 
 500         return (0);
 501 }
 502 
 503 static int
 504 drm_do_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
 505 {
 506         drm_device_dma_t *dma = dev->dma;
 507         drm_buf_entry_t *entry;
 508         drm_buf_t *buf;
 509         unsigned long offset;
 510         unsigned long agp_offset;
 511         int count;
 512         int order;
 513         int size;
 514         int alignment;
 515         int page_order;
 516         int byte_count;
 517         int i;
 518         drm_buf_t **temp_buflist;
 519 
 520         count = request->count;
 521         order = drm_order(request->size);
 522         size = 1 << order;
 523 
 524         alignment  = (request->flags & _DRM_PAGE_ALIGN)
 525             ? round_page(size) : size;
 526         page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
 527 
 528         byte_count = 0;
 529         agp_offset = request->agp_start;
 530         entry = &dma->bufs[order];
 531 
 532         entry->buflist = drm_alloc(count * sizeof (*entry->buflist),
 533             DRM_MEM_BUFS);
 534         if (entry->buflist == NULL)
 535                 return (ENOMEM);
 536 
 537         entry->buf_size = size;
 538         entry->page_order = page_order;
 539 
 540         offset = 0;
 541 
 542         while (entry->buf_count < count) {
 543                 buf             = &entry->buflist[entry->buf_count];
 544                 buf->idx     = dma->buf_count + entry->buf_count;
 545                 buf->total   = alignment;
 546                 buf->order   = order;
 547                 buf->used    = 0;
 548 
 549                 buf->offset  = (dma->byte_count + offset);
 550                 buf->bus_address = agp_offset + offset;
 551                 buf->address = (void *)(agp_offset + offset + dev->sg->handle);
 552                 buf->next    = NULL;
 553                 buf->pending = 0;
 554                 buf->filp    = NULL;
 555 
 556                 buf->dev_priv_size = dev->driver->buf_priv_size;
 557                 buf->dev_private = drm_alloc(buf->dev_priv_size,
 558                     DRM_MEM_BUFS);
 559                 if (buf->dev_private == NULL) {
 560                         /* Set count correctly so we free the proper amount. */
 561                         entry->buf_count = count;
 562                         drm_cleanup_buf_error(dev, entry);
 563                         return (ENOMEM);
 564                 }
 565 
 566                 offset += alignment;
 567                 entry->buf_count++;
 568                 byte_count += PAGE_SIZE << page_order;
 569         }
 570 
 571         temp_buflist = drm_realloc(dma->buflist,
 572             dma->buf_count * sizeof (*dma->buflist),
 573             (dma->buf_count + entry->buf_count)
 574             * sizeof (*dma->buflist), DRM_MEM_BUFS);
 575         if (!temp_buflist) {
 576                 drm_cleanup_buf_error(dev, entry);
 577                 return (ENOMEM);
 578         }
 579         dma->buflist = temp_buflist;
 580 
 581         for (i = 0; i < entry->buf_count; i++) {
 582                 dma->buflist[i + dma->buf_count] = &entry->buflist[i];
 583         }
 584 
 585         dma->buf_count += entry->buf_count;
 586         dma->byte_count += byte_count;
 587         request->count = entry->buf_count;
 588         request->size = size;
 589         dma->flags = _DRM_DMA_USE_SG;
 590 
 591         return (0);
 592 }
 593 
 594 int
 595 drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request)
 596 {
 597         int order, ret;
 598 
 599         DRM_SPINLOCK(&dev->dma_lock);
 600 
 601         if (request->count < 0 || request->count > 4096) {
 602                 DRM_SPINLOCK(&dev->dma_lock);
 603                 return (EINVAL);
 604         }
 605 
 606         order = drm_order(request->size);
 607         if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) {
 608                 DRM_SPINLOCK(&dev->dma_lock);
 609                 return (EINVAL);
 610         }
 611 
 612         /* No more allocations after first buffer-using ioctl. */
 613         if (dev->buf_use != 0) {
 614                 DRM_SPINUNLOCK(&dev->dma_lock);
 615                 return (EBUSY);
 616         }
 617         /* No more than one allocation per order */
 618         if (dev->dma->bufs[order].buf_count != 0) {
 619                 DRM_SPINUNLOCK(&dev->dma_lock);
 620                 return (ENOMEM);
 621         }
 622 
 623         ret = drm_do_addbufs_agp(dev, request);
 624 
 625         DRM_SPINUNLOCK(&dev->dma_lock);
 626 
 627         return (ret);
 628 }
 629 
 630 int
 631 drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)
 632 {
 633         int order, ret;
 634 
 635         DRM_SPINLOCK(&dev->dma_lock);
 636 
 637         if (request->count < 0 || request->count > 4096) {
 638                 DRM_SPINUNLOCK(&dev->dma_lock);
 639                 return (EINVAL);
 640         }
 641 
 642         order = drm_order(request->size);
 643         if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) {
 644                 DRM_SPINUNLOCK(&dev->dma_lock);
 645                 return (EINVAL);
 646         }
 647 
 648         /* No more allocations after first buffer-using ioctl. */
 649         if (dev->buf_use != 0) {
 650                 DRM_SPINUNLOCK(&dev->dma_lock);
 651                 return (EBUSY);
 652         }
 653 
 654         /* No more than one allocation per order */
 655         if (dev->dma->bufs[order].buf_count != 0) {
 656                 DRM_SPINUNLOCK(&dev->dma_lock);
 657                 return (ENOMEM);
 658         }
 659 
 660         ret = drm_do_addbufs_sg(dev, request);
 661         DRM_SPINUNLOCK(&dev->dma_lock);
 662         return (ret);
 663 }
 664 
 665 /*ARGSUSED*/
 666 int
 667 drm_addbufs_ioctl(DRM_IOCTL_ARGS)
 668 {
 669         DRM_DEVICE;
 670         drm_buf_desc_t request;
 671         int err;
 672 
 673 #ifdef  _MULTI_DATAMODEL
 674         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 675                 drm_buf_desc_32_t request32;
 676                 DRM_COPYFROM_WITH_RETURN(&request32,
 677                     (void *)data, sizeof (request32));
 678                 request.count = request32.count;
 679                 request.size = request32.size;
 680                 request.low_mark = request32.low_mark;
 681                 request.high_mark = request32.high_mark;
 682                 request.flags = request32.flags;
 683                 request.agp_start = request32.agp_start;
 684         } else
 685 #endif
 686                 DRM_COPYFROM_WITH_RETURN(&request,
 687                     (void *)data, sizeof (request));
 688 
 689         if (request.flags & _DRM_AGP_BUFFER)
 690                 err = drm_addbufs_agp(dev, &request);
 691         else if (request.flags & _DRM_SG_BUFFER)
 692                 err = drm_addbufs_sg(dev, &request);
 693 
 694 #ifdef  _MULTI_DATAMODEL
 695         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 696                 drm_buf_desc_32_t request32;
 697                 request32.count = request.count;
 698                 request32.size = request.size;
 699                 request32.low_mark = request.low_mark;
 700                 request32.high_mark = request.high_mark;
 701                 request32.flags = request.flags;
 702                 request32.agp_start = (uint32_t)request.agp_start;
 703                 DRM_COPYTO_WITH_RETURN((void *)data,
 704                     &request32, sizeof (request32));
 705         } else
 706 #endif
 707                 DRM_COPYTO_WITH_RETURN((void *)data,
 708                     &request, sizeof (request));
 709 
 710         return (err);
 711 }
 712 
 713 /*ARGSUSED*/
 714 int
 715 drm_freebufs(DRM_IOCTL_ARGS)
 716 {
 717         DRM_DEVICE;
 718         drm_device_dma_t *dma = dev->dma;
 719         drm_buf_free_t request;
 720         int i;
 721         int idx;
 722         drm_buf_t *buf;
 723         int retcode = 0;
 724 
 725 #ifdef  _MULTI_DATAMODEL
 726         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 727                 drm_buf_free_32_t request32;
 728                 DRM_COPYFROM_WITH_RETURN(&request32,
 729                     (void*)data, sizeof (request32));
 730                 request.count = request32.count;
 731                 request.list = (int *)(uintptr_t)request32.list;
 732         } else
 733 #endif
 734                 DRM_COPYFROM_WITH_RETURN(&request,
 735                     (void *)data, sizeof (request));
 736 
 737         for (i = 0; i < request.count; i++) {
 738                 if (DRM_COPY_FROM_USER(&idx, &request.list[i], sizeof (idx))) {
 739                         retcode = EFAULT;
 740                         break;
 741                 }
 742                 if (idx < 0 || idx >= dma->buf_count) {
 743                         DRM_ERROR("drm_freebufs: Index %d (of %d max)\n",
 744                             idx, dma->buf_count - 1);
 745                         retcode = EINVAL;
 746                         break;
 747                 }
 748                 buf = dma->buflist[idx];
 749                 if (buf->filp != fpriv) {
 750                         DRM_ERROR(
 751                             "drm_freebufs: process %d not owning the buffer.\n",
 752                             DRM_CURRENTPID);
 753                         retcode = EINVAL;
 754                         break;
 755                 }
 756                 drm_free_buffer(dev, buf);
 757         }
 758 
 759         return (retcode);
 760 }
 761 
 762 #ifdef _LP64
 763 extern caddr_t smmap64(caddr_t, size_t, int, int, int, off_t);
 764 #define drm_smmap       smmap64
 765 #else
 766 #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
 767 extern caddr_t smmap32(caddr32_t, size32_t, int, int, int, off32_t);
 768 #define drm_smmap smmap32
 769 #else
 770 #error "No define for _LP64, _SYSCALL32_IMPL or _ILP32"
 771 #endif
 772 #endif
 773 
 774 
 775 /*ARGSUSED*/
 776 int
 777 drm_mapbufs(DRM_IOCTL_ARGS)
 778 {
 779         DRM_DEVICE;
 780         drm_buf_map_t request;
 781         const int zero = 0;
 782         unsigned long   vaddr;
 783         unsigned long address;
 784         drm_device_dma_t *dma = dev->dma;
 785         uint_t  size;
 786         uint_t  foff;
 787         int             ret_tmp;
 788         int     i;
 789 
 790 #ifdef  _MULTI_DATAMODEL
 791         drm_buf_map_32_t request32;
 792         drm_buf_pub_32_t        *list32;
 793         uint_t          address32;
 794 
 795         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 796                 DRM_COPYFROM_WITH_RETURN(&request32,
 797                     (void *)data, sizeof (request32));
 798                 request.count = request32.count;
 799                 request.virtual = (void *)(uintptr_t)request32.virtual;
 800                 request.list = (drm_buf_pub_t *)(uintptr_t)request32.list;
 801                 request.fd = request32.fd;
 802         } else
 803 #endif
 804                 DRM_COPYFROM_WITH_RETURN(&request,
 805                     (void *)data, sizeof (request));
 806 
 807         dev->buf_use++;
 808 
 809         if (request.count < dma->buf_count)
 810                 goto done;
 811 
 812         if ((dev->driver->use_agp && (dma->flags & _DRM_DMA_USE_AGP)) ||
 813             (dev->driver->use_sg && (dma->flags & _DRM_DMA_USE_SG))) {
 814                 drm_local_map_t *map = dev->agp_buffer_map;
 815                 if (map == NULL)
 816                         return (EINVAL);
 817                 size = round_page(map->size);
 818                 foff = (uintptr_t)map->handle;
 819         } else {
 820                 size = round_page(dma->byte_count);
 821                 foff = 0;
 822         }
 823         request.virtual = drm_smmap(NULL, size, PROT_READ | PROT_WRITE,
 824             MAP_SHARED, request.fd, foff);
 825         if (request.virtual == NULL) {
 826                 DRM_ERROR("drm_mapbufs: request.virtual is NULL");
 827                 return (EINVAL);
 828         }
 829 
 830         vaddr = (unsigned long) request.virtual;
 831 #ifdef  _MULTI_DATAMODEL
 832         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 833                 list32 = (drm_buf_pub_32_t *)(uintptr_t)request32.list;
 834                 for (i = 0; i < dma->buf_count; i++) {
 835                         if (DRM_COPY_TO_USER(&list32[i].idx,
 836                             &dma->buflist[i]->idx, sizeof (list32[0].idx))) {
 837                                 return (EFAULT);
 838                         }
 839                         if (DRM_COPY_TO_USER(&list32[i].total,
 840                             &dma->buflist[i]->total,
 841                             sizeof (list32[0].total))) {
 842                                 return (EFAULT);
 843                         }
 844                         if (DRM_COPY_TO_USER(&list32[i].used,
 845                             &zero, sizeof (zero))) {
 846                                 return (EFAULT);
 847                         }
 848                         address32 = vaddr + dma->buflist[i]->offset; /* *** */
 849                         ret_tmp = DRM_COPY_TO_USER(&list32[i].address,
 850                             &address32, sizeof (list32[0].address));
 851                         if (ret_tmp)
 852                                 return (EFAULT);
 853                 }
 854                 goto done;
 855         }
 856 #endif
 857 
 858         ASSERT(ddi_model_convert_from(mode & FMODELS) != DDI_MODEL_ILP32);
 859         for (i = 0; i < dma->buf_count; i++) {
 860                 if (DRM_COPY_TO_USER(&request.list[i].idx,
 861                     &dma->buflist[i]->idx, sizeof (request.list[0].idx))) {
 862                         return (EFAULT);
 863                 }
 864                 if (DRM_COPY_TO_USER(&request.list[i].total,
 865                     &dma->buflist[i]->total, sizeof (request.list[0].total))) {
 866                         return (EFAULT);
 867                 }
 868                 if (DRM_COPY_TO_USER(&request.list[i].used, &zero,
 869                     sizeof (zero))) {
 870                         return (EFAULT);
 871                 }
 872                 address = vaddr + dma->buflist[i]->offset; /* *** */
 873 
 874                 ret_tmp = DRM_COPY_TO_USER(&request.list[i].address,
 875                     &address, sizeof (address));
 876                 if (ret_tmp) {
 877                         return (EFAULT);
 878                 }
 879         }
 880 
 881 done:
 882 #ifdef  _MULTI_DATAMODEL
 883         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 884                 request32.count = dma->buf_count;
 885                 request32.virtual = (caddr32_t)(uintptr_t)request.virtual;
 886                 DRM_COPYTO_WITH_RETURN((void *)data,
 887                     &request32, sizeof (request32));
 888         } else {
 889 #endif
 890                 request.count = dma->buf_count;
 891                 DRM_COPYTO_WITH_RETURN((void *)data,
 892                     &request, sizeof (request));
 893 #ifdef  _MULTI_DATAMODEL
 894         }
 895 #endif
 896         return (0);
 897 }