drm_bufs.c revision 145478
1145132Sanholt/* drm_bufs.h -- Generic buffer template -*- linux-c -*- 2145132Sanholt * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com 3145132Sanholt */ 4145132Sanholt/*- 5145132Sanholt * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 6145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 7145132Sanholt * All Rights Reserved. 8145132Sanholt * 9145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 10145132Sanholt * copy of this software and associated documentation files (the "Software"), 11145132Sanholt * to deal in the Software without restriction, including without limitation 12145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 14145132Sanholt * Software is furnished to do so, subject to the following conditions: 15145132Sanholt * 16145132Sanholt * The above copyright notice and this permission notice (including the next 17145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 18145132Sanholt * Software. 19145132Sanholt * 20145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23145132Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26145132Sanholt * OTHER DEALINGS IN THE SOFTWARE. 27145132Sanholt * 28145132Sanholt * Authors: 29145132Sanholt * Rickard E. (Rik) Faith <faith@valinux.com> 30145132Sanholt * Gareth Hughes <gareth@valinux.com> 31145132Sanholt * 32145132Sanholt * $FreeBSD: head/sys/dev/drm/drm_bufs.c 145478 2005-04-24 19:03:32Z anholt $ 33145132Sanholt */ 34145132Sanholt 35145132Sanholt#include "dev/drm/drmP.h" 36145132Sanholt 37145132Sanholt/* 38145132Sanholt * Compute order. Can be made faster. 39145132Sanholt */ 40145132Sanholtint drm_order(unsigned long size) 41145132Sanholt{ 42145132Sanholt int order; 43145132Sanholt unsigned long tmp; 44145132Sanholt 45145132Sanholt for ( order = 0, tmp = size ; tmp >>= 1 ; ++order ); 46145132Sanholt 47145132Sanholt if ( size & ~(1 << order) ) 48145132Sanholt ++order; 49145132Sanholt 50145132Sanholt return order; 51145132Sanholt} 52145132Sanholt 53145132Sanholtunsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource) 54145132Sanholt{ 55145132Sanholt struct resource *bsr; 56145132Sanholt unsigned long offset; 57145132Sanholt 58145132Sanholt resource = resource * 4 + 0x10; 59145132Sanholt 60145132Sanholt bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &resource, 61145132Sanholt RF_ACTIVE | RF_SHAREABLE); 62145132Sanholt if (bsr == NULL) { 63145132Sanholt DRM_ERROR("Couldn't find resource 0x%x\n", resource); 64145132Sanholt return 0; 65145132Sanholt } 66145132Sanholt 67145132Sanholt offset = rman_get_start(bsr); 68145132Sanholt 69145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, resource, bsr); 70145132Sanholt 71145132Sanholt return offset; 72145132Sanholt} 73145132Sanholt 74145132Sanholtunsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) 75145132Sanholt{ 76145132Sanholt struct resource *bsr; 77145132Sanholt unsigned long len; 78145132Sanholt 79145132Sanholt resource = resource * 4 + 0x10; 80145132Sanholt 81145132Sanholt bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &resource, 82145132Sanholt RF_ACTIVE | RF_SHAREABLE); 83145132Sanholt if (bsr == NULL) { 84145132Sanholt DRM_ERROR("Couldn't find resource 0x%x\n", resource); 85145132Sanholt return ENOMEM; 86145132Sanholt } 87145132Sanholt 88145132Sanholt len = rman_get_size(bsr); 89145132Sanholt 90145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, resource, bsr); 91145132Sanholt 92145132Sanholt return len; 93145132Sanholt} 94145132Sanholt 95145132Sanholtint drm_initmap(drm_device_t *dev, unsigned long start, unsigned long len, 96145132Sanholt unsigned int resource, int type, int flags) 97145132Sanholt{ 98145132Sanholt drm_local_map_t *map; 99145132Sanholt struct resource *bsr; 100145132Sanholt 101145132Sanholt if (type != _DRM_REGISTERS && type != _DRM_FRAME_BUFFER) 102145132Sanholt return EINVAL; 103145132Sanholt if (len == 0) 104145132Sanholt return EINVAL; 105145132Sanholt 106145132Sanholt map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT); 107145132Sanholt if (map == NULL) 108145132Sanholt return ENOMEM; 109145132Sanholt 110145132Sanholt map->rid = resource * 4 + 0x10; 111145132Sanholt bsr = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &map->rid, 112145132Sanholt RF_ACTIVE | RF_SHAREABLE); 113145132Sanholt if (bsr == NULL) { 114145132Sanholt DRM_ERROR("Couldn't allocate %s resource\n", 115145132Sanholt ((type == _DRM_REGISTERS) ? "mmio" : "framebuffer")); 116145132Sanholt free(map, M_DRM); 117145132Sanholt return ENOMEM; 118145132Sanholt } 119145132Sanholt 120145132Sanholt map->kernel_owned = 1; 121145132Sanholt map->type = type; 122145132Sanholt map->flags = flags; 123145132Sanholt map->bsr = bsr; 124145132Sanholt map->bst = rman_get_bustag(bsr); 125145132Sanholt map->bsh = rman_get_bushandle(bsr); 126145132Sanholt map->offset = start; 127145132Sanholt map->size = len; 128145132Sanholt 129145132Sanholt if (type == _DRM_REGISTERS) 130145132Sanholt map->handle = rman_get_virtual(bsr); 131145132Sanholt 132145132Sanholt DRM_DEBUG("initmap %d,0x%x@0x%lx/0x%lx\n", map->type, map->flags, 133145132Sanholt map->offset, map->size); 134145132Sanholt 135145132Sanholt if (map->flags & _DRM_WRITE_COMBINING) { 136145132Sanholt int err; 137145132Sanholt 138145132Sanholt err = drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC); 139145132Sanholt if (err == 0) 140145132Sanholt map->mtrr = 1; 141145132Sanholt } 142145132Sanholt 143145132Sanholt DRM_LOCK(); 144145132Sanholt TAILQ_INSERT_TAIL(&dev->maplist, map, link); 145145132Sanholt DRM_UNLOCK(); 146145132Sanholt 147145132Sanholt return 0; 148145132Sanholt} 149145132Sanholt 150145132Sanholtint drm_addmap(DRM_IOCTL_ARGS) 151145132Sanholt{ 152145132Sanholt DRM_DEVICE; 153145132Sanholt drm_map_t request; 154145132Sanholt drm_local_map_t *map; 155145132Sanholt dma_addr_t bus_addr; 156145132Sanholt 157145132Sanholt if (!(dev->flags & (FREAD|FWRITE))) 158145132Sanholt return DRM_ERR(EACCES); /* Require read/write */ 159145132Sanholt 160145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(drm_map_t) ); 161145132Sanholt 162145132Sanholt /* Only allow shared memory to be removable since we only keep enough 163145132Sanholt * book keeping information about shared memory to allow for removal 164145132Sanholt * when processes fork. 165145132Sanholt */ 166145132Sanholt if ((request.flags & _DRM_REMOVABLE) && request.type != _DRM_SHM) 167145132Sanholt return EINVAL; 168145132Sanholt if ((request.offset & PAGE_MASK) || (request.size & PAGE_MASK)) 169145132Sanholt return EINVAL; 170145132Sanholt if (request.offset + request.size < request.offset) 171145132Sanholt return EINVAL; 172145132Sanholt 173145132Sanholt DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", 174145132Sanholt request.offset, request.size, request.type); 175145132Sanholt 176145132Sanholt /* Check if this is just another version of a kernel-allocated map, and 177145132Sanholt * just hand that back if so. 178145132Sanholt */ 179145132Sanholt if (request.type == _DRM_REGISTERS || request.type == _DRM_FRAME_BUFFER) 180145132Sanholt { 181145132Sanholt DRM_LOCK(); 182145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 183145132Sanholt if (map->kernel_owned && map->type == request.type && 184145132Sanholt map->offset == request.offset) { 185145132Sanholt /* XXX: this size setting is questionable. */ 186145132Sanholt map->size = request.size; 187145132Sanholt DRM_DEBUG("Found kernel map %d\n", request.type); 188145132Sanholt goto done; 189145132Sanholt } 190145132Sanholt } 191145132Sanholt DRM_UNLOCK(); 192145132Sanholt } 193145132Sanholt 194145132Sanholt /* Allocate a new map structure, fill it in, and do any type-specific 195145132Sanholt * initialization necessary. 196145132Sanholt */ 197145132Sanholt map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT); 198145132Sanholt if ( !map ) 199145132Sanholt return DRM_ERR(ENOMEM); 200145132Sanholt 201145132Sanholt map->offset = request.offset; 202145132Sanholt map->size = request.size; 203145132Sanholt map->type = request.type; 204145132Sanholt map->flags = request.flags; 205145132Sanholt 206145132Sanholt switch ( map->type ) { 207145132Sanholt case _DRM_REGISTERS: 208145478Sanholt map->handle = drm_ioremap(dev, map); 209145132Sanholt if (!(map->flags & _DRM_WRITE_COMBINING)) 210145132Sanholt break; 211145132Sanholt /* FALLTHROUGH */ 212145132Sanholt case _DRM_FRAME_BUFFER: 213145132Sanholt if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 214145132Sanholt map->mtrr = 1; 215145132Sanholt break; 216145132Sanholt case _DRM_SHM: 217145132Sanholt map->handle = malloc(map->size, M_DRM, M_NOWAIT); 218145132Sanholt DRM_DEBUG( "%lu %d %p\n", 219145132Sanholt map->size, drm_order(map->size), map->handle ); 220145132Sanholt if ( !map->handle ) { 221145132Sanholt free(map, M_DRM); 222145132Sanholt return DRM_ERR(ENOMEM); 223145132Sanholt } 224145132Sanholt map->offset = (unsigned long)map->handle; 225145132Sanholt if ( map->flags & _DRM_CONTAINS_LOCK ) { 226145132Sanholt /* Prevent a 2nd X Server from creating a 2nd lock */ 227145132Sanholt DRM_LOCK(); 228145132Sanholt if (dev->lock.hw_lock != NULL) { 229145132Sanholt DRM_UNLOCK(); 230145132Sanholt free(map->handle, M_DRM); 231145132Sanholt free(map, M_DRM); 232145132Sanholt return DRM_ERR(EBUSY); 233145132Sanholt } 234145132Sanholt dev->lock.hw_lock = map->handle; /* Pointer to lock */ 235145132Sanholt DRM_UNLOCK(); 236145132Sanholt } 237145132Sanholt break; 238145132Sanholt case _DRM_AGP: 239145132Sanholt map->offset += dev->agp->base; 240145132Sanholt map->mtrr = dev->agp->mtrr; /* for getmap */ 241145132Sanholt break; 242145132Sanholt case _DRM_SCATTER_GATHER: 243145132Sanholt if (!dev->sg) { 244145132Sanholt free(map, M_DRM); 245145132Sanholt return DRM_ERR(EINVAL); 246145132Sanholt } 247145132Sanholt map->offset = map->offset + dev->sg->handle; 248145132Sanholt break; 249145132Sanholt case _DRM_CONSISTENT: 250145132Sanholt map->handle = drm_pci_alloc(dev, map->size, map->size, 251145132Sanholt 0xfffffffful, &bus_addr); 252145132Sanholt if (map->handle == NULL) { 253145132Sanholt free(map, M_DRM); 254145132Sanholt return ENOMEM; 255145132Sanholt } 256145132Sanholt map->offset = (unsigned long)bus_addr; 257145132Sanholt break; 258145132Sanholt default: 259145132Sanholt free(map, M_DRM); 260145132Sanholt return DRM_ERR(EINVAL); 261145132Sanholt } 262145132Sanholt 263145132Sanholt DRM_LOCK(); 264145132Sanholt TAILQ_INSERT_TAIL(&dev->maplist, map, link); 265145132Sanholt 266145132Sanholtdone: 267145132Sanholt /* Jumped to, with lock held, when a kernel map is found. */ 268145132Sanholt request.offset = map->offset; 269145132Sanholt request.size = map->size; 270145132Sanholt request.type = map->type; 271145132Sanholt request.flags = map->flags; 272145132Sanholt request.mtrr = map->mtrr; 273145132Sanholt request.handle = map->handle; 274145132Sanholt DRM_UNLOCK(); 275145132Sanholt 276145132Sanholt DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", request.type, request.offset, request.size); 277145132Sanholt 278145132Sanholt if ( request.type != _DRM_SHM ) { 279145132Sanholt request.handle = (void *)request.offset; 280145132Sanholt } 281145132Sanholt 282145132Sanholt DRM_COPY_TO_USER_IOCTL( (drm_map_t *)data, request, sizeof(drm_map_t) ); 283145132Sanholt 284145132Sanholt return 0; 285145132Sanholt} 286145132Sanholt 287145132Sanholtvoid drm_remove_map(drm_device_t *dev, drm_local_map_t *map) 288145132Sanholt{ 289145132Sanholt DRM_SPINLOCK_ASSERT(&dev->dev_lock); 290145132Sanholt 291145132Sanholt TAILQ_REMOVE(&dev->maplist, map, link); 292145132Sanholt 293145132Sanholt switch (map->type) { 294145132Sanholt case _DRM_REGISTERS: 295145132Sanholt if (map->bsr == NULL) 296145132Sanholt drm_ioremapfree(map); 297145132Sanholt /* FALLTHROUGH */ 298145132Sanholt case _DRM_FRAME_BUFFER: 299145132Sanholt if (map->mtrr) { 300145132Sanholt int __unused retcode; 301145132Sanholt 302145132Sanholt retcode = drm_mtrr_del(map->offset, map->size, 303145132Sanholt DRM_MTRR_WC); 304145132Sanholt DRM_DEBUG("mtrr_del = %d\n", retcode); 305145132Sanholt } 306145132Sanholt break; 307145132Sanholt case _DRM_SHM: 308145132Sanholt free(map->handle, M_DRM); 309145132Sanholt break; 310145132Sanholt case _DRM_AGP: 311145132Sanholt case _DRM_SCATTER_GATHER: 312145132Sanholt break; 313145132Sanholt case _DRM_CONSISTENT: 314145132Sanholt drm_pci_free(dev, map->size, map->handle, map->offset); 315145132Sanholt break; 316145132Sanholt } 317145132Sanholt 318145132Sanholt if (map->bsr != NULL) { 319145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 320145132Sanholt map->bsr); 321145132Sanholt } 322145132Sanholt 323145132Sanholt free(map, M_DRM); 324145132Sanholt} 325145132Sanholt 326145132Sanholt/* Remove a map private from list and deallocate resources if the mapping 327145132Sanholt * isn't in use. 328145132Sanholt */ 329145132Sanholt 330145132Sanholtint drm_rmmap(DRM_IOCTL_ARGS) 331145132Sanholt{ 332145132Sanholt DRM_DEVICE; 333145132Sanholt drm_local_map_t *map; 334145132Sanholt drm_map_t request; 335145132Sanholt 336145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(request) ); 337145132Sanholt 338145132Sanholt DRM_LOCK(); 339145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 340145132Sanholt if (map->handle == request.handle && 341145132Sanholt map->flags & _DRM_REMOVABLE) 342145132Sanholt break; 343145132Sanholt } 344145132Sanholt 345145132Sanholt /* No match found. */ 346145132Sanholt if (map == NULL) { 347145132Sanholt DRM_UNLOCK(); 348145132Sanholt return DRM_ERR(EINVAL); 349145132Sanholt } 350145132Sanholt 351145132Sanholt drm_remove_map(dev, map); 352145132Sanholt 353145132Sanholt DRM_UNLOCK(); 354145132Sanholt 355145132Sanholt return 0; 356145132Sanholt} 357145132Sanholt 358145132Sanholt 359145132Sanholtstatic void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry) 360145132Sanholt{ 361145132Sanholt int i; 362145132Sanholt 363145132Sanholt if (entry->seg_count) { 364145132Sanholt for (i = 0; i < entry->seg_count; i++) { 365145132Sanholt drm_pci_free(dev, entry->buf_size, 366145132Sanholt (void *)entry->seglist[i], 367145132Sanholt entry->seglist_bus[i]); 368145132Sanholt } 369145132Sanholt free(entry->seglist, M_DRM); 370145132Sanholt free(entry->seglist_bus, M_DRM); 371145132Sanholt 372145132Sanholt entry->seg_count = 0; 373145132Sanholt } 374145132Sanholt 375145132Sanholt if (entry->buf_count) { 376145132Sanholt for (i = 0; i < entry->buf_count; i++) { 377145132Sanholt free(entry->buflist[i].dev_private, M_DRM); 378145132Sanholt } 379145132Sanholt free(entry->buflist, M_DRM); 380145132Sanholt 381145132Sanholt entry->buf_count = 0; 382145132Sanholt } 383145132Sanholt} 384145132Sanholt 385145132Sanholtstatic int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request) 386145132Sanholt{ 387145132Sanholt drm_device_dma_t *dma = dev->dma; 388145132Sanholt drm_buf_entry_t *entry; 389145132Sanholt drm_buf_t *buf; 390145132Sanholt unsigned long offset; 391145132Sanholt unsigned long agp_offset; 392145132Sanholt int count; 393145132Sanholt int order; 394145132Sanholt int size; 395145132Sanholt int alignment; 396145132Sanholt int page_order; 397145132Sanholt int total; 398145132Sanholt int byte_count; 399145132Sanholt int i; 400145132Sanholt drm_buf_t **temp_buflist; 401145132Sanholt 402145132Sanholt count = request->count; 403145132Sanholt order = drm_order(request->size); 404145132Sanholt size = 1 << order; 405145132Sanholt 406145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 407145132Sanholt ? round_page(size) : size; 408145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 409145132Sanholt total = PAGE_SIZE << page_order; 410145132Sanholt 411145132Sanholt byte_count = 0; 412145132Sanholt agp_offset = dev->agp->base + request->agp_start; 413145132Sanholt 414145132Sanholt DRM_DEBUG( "count: %d\n", count ); 415145132Sanholt DRM_DEBUG( "order: %d\n", order ); 416145132Sanholt DRM_DEBUG( "size: %d\n", size ); 417145132Sanholt DRM_DEBUG( "agp_offset: 0x%lx\n", agp_offset ); 418145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 419145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 420145132Sanholt DRM_DEBUG( "total: %d\n", total ); 421145132Sanholt 422145132Sanholt entry = &dma->bufs[order]; 423145132Sanholt 424145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 425145132Sanholt M_NOWAIT | M_ZERO); 426145132Sanholt if ( !entry->buflist ) { 427145132Sanholt return DRM_ERR(ENOMEM); 428145132Sanholt } 429145132Sanholt 430145132Sanholt entry->buf_size = size; 431145132Sanholt entry->page_order = page_order; 432145132Sanholt 433145132Sanholt offset = 0; 434145132Sanholt 435145132Sanholt while ( entry->buf_count < count ) { 436145132Sanholt buf = &entry->buflist[entry->buf_count]; 437145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 438145132Sanholt buf->total = alignment; 439145132Sanholt buf->order = order; 440145132Sanholt buf->used = 0; 441145132Sanholt 442145132Sanholt buf->offset = (dma->byte_count + offset); 443145132Sanholt buf->bus_address = agp_offset + offset; 444145132Sanholt buf->address = (void *)(agp_offset + offset); 445145132Sanholt buf->next = NULL; 446145132Sanholt buf->pending = 0; 447145132Sanholt buf->filp = NULL; 448145132Sanholt 449145132Sanholt buf->dev_priv_size = dev->dev_priv_size; 450145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 451145132Sanholt M_NOWAIT | M_ZERO); 452145132Sanholt if (buf->dev_private == NULL) { 453145132Sanholt /* Set count correctly so we free the proper amount. */ 454145132Sanholt entry->buf_count = count; 455145132Sanholt drm_cleanup_buf_error(dev, entry); 456145132Sanholt return DRM_ERR(ENOMEM); 457145132Sanholt } 458145132Sanholt 459145132Sanholt offset += alignment; 460145132Sanholt entry->buf_count++; 461145132Sanholt byte_count += PAGE_SIZE << page_order; 462145132Sanholt } 463145132Sanholt 464145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 465145132Sanholt 466145132Sanholt temp_buflist = realloc(dma->buflist, 467145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 468145132Sanholt M_NOWAIT); 469145132Sanholt if (temp_buflist == NULL) { 470145132Sanholt /* Free the entry because it isn't valid */ 471145132Sanholt drm_cleanup_buf_error(dev, entry); 472145132Sanholt return DRM_ERR(ENOMEM); 473145132Sanholt } 474145132Sanholt dma->buflist = temp_buflist; 475145132Sanholt 476145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 477145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 478145132Sanholt } 479145132Sanholt 480145132Sanholt dma->buf_count += entry->buf_count; 481145132Sanholt dma->byte_count += byte_count; 482145132Sanholt 483145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 484145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 485145132Sanholt 486145132Sanholt request->count = entry->buf_count; 487145132Sanholt request->size = size; 488145132Sanholt 489145132Sanholt dma->flags = _DRM_DMA_USE_AGP; 490145132Sanholt 491145132Sanholt return 0; 492145132Sanholt} 493145132Sanholt 494145132Sanholtstatic int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request) 495145132Sanholt{ 496145132Sanholt drm_device_dma_t *dma = dev->dma; 497145132Sanholt int count; 498145132Sanholt int order; 499145132Sanholt int size; 500145132Sanholt int total; 501145132Sanholt int page_order; 502145132Sanholt drm_buf_entry_t *entry; 503145132Sanholt vm_offset_t vaddr; 504145132Sanholt drm_buf_t *buf; 505145132Sanholt int alignment; 506145132Sanholt unsigned long offset; 507145132Sanholt int i; 508145132Sanholt int byte_count; 509145132Sanholt int page_count; 510145132Sanholt unsigned long *temp_pagelist; 511145132Sanholt drm_buf_t **temp_buflist; 512145132Sanholt dma_addr_t bus_addr; 513145132Sanholt 514145132Sanholt count = request->count; 515145132Sanholt order = drm_order(request->size); 516145132Sanholt size = 1 << order; 517145132Sanholt 518145132Sanholt DRM_DEBUG( "count=%d, size=%d (%d), order=%d\n", 519145132Sanholt request->count, request->size, size, order ); 520145132Sanholt 521145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 522145132Sanholt ? round_page(size) : size; 523145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 524145132Sanholt total = PAGE_SIZE << page_order; 525145132Sanholt 526145132Sanholt entry = &dma->bufs[order]; 527145132Sanholt 528145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 529145132Sanholt M_NOWAIT | M_ZERO); 530145132Sanholt entry->seglist = malloc(count * sizeof(*entry->seglist), M_DRM, 531145132Sanholt M_NOWAIT | M_ZERO); 532145132Sanholt entry->seglist_bus = malloc(count * sizeof(*entry->seglist_bus), M_DRM, 533145132Sanholt M_NOWAIT | M_ZERO); 534145132Sanholt 535145132Sanholt /* Keep the original pagelist until we know all the allocations 536145132Sanholt * have succeeded 537145132Sanholt */ 538145132Sanholt temp_pagelist = malloc((dma->page_count + (count << page_order)) * 539145132Sanholt sizeof(*dma->pagelist), M_DRM, M_NOWAIT); 540145132Sanholt 541145132Sanholt if (entry->buflist == NULL || entry->seglist == NULL || 542145132Sanholt entry->seglist_bus == NULL || temp_pagelist == NULL) { 543145132Sanholt free(entry->buflist, M_DRM); 544145132Sanholt free(entry->seglist, M_DRM); 545145132Sanholt free(entry->seglist_bus, M_DRM); 546145132Sanholt return DRM_ERR(ENOMEM); 547145132Sanholt } 548145132Sanholt 549145132Sanholt memcpy(temp_pagelist, dma->pagelist, dma->page_count * 550145132Sanholt sizeof(*dma->pagelist)); 551145132Sanholt 552145132Sanholt DRM_DEBUG( "pagelist: %d entries\n", 553145132Sanholt dma->page_count + (count << page_order) ); 554145132Sanholt 555145132Sanholt entry->buf_size = size; 556145132Sanholt entry->page_order = page_order; 557145132Sanholt byte_count = 0; 558145132Sanholt page_count = 0; 559145132Sanholt 560145132Sanholt while ( entry->buf_count < count ) { 561145132Sanholt vaddr = (vm_offset_t)drm_pci_alloc(dev, size, alignment, 562145132Sanholt 0xfffffffful, &bus_addr); 563145132Sanholt if (vaddr == 0) { 564145132Sanholt /* Set count correctly so we free the proper amount. */ 565145132Sanholt entry->buf_count = count; 566145132Sanholt entry->seg_count = count; 567145132Sanholt drm_cleanup_buf_error(dev, entry); 568145132Sanholt free(temp_pagelist, M_DRM); 569145132Sanholt return DRM_ERR(ENOMEM); 570145132Sanholt } 571145132Sanholt 572145132Sanholt entry->seglist_bus[entry->seg_count] = bus_addr; 573145132Sanholt entry->seglist[entry->seg_count++] = vaddr; 574145132Sanholt for ( i = 0 ; i < (1 << page_order) ; i++ ) { 575145132Sanholt DRM_DEBUG( "page %d @ 0x%08lx\n", 576145132Sanholt dma->page_count + page_count, 577145132Sanholt (long)vaddr + PAGE_SIZE * i ); 578145132Sanholt temp_pagelist[dma->page_count + page_count++] = 579145132Sanholt vaddr + PAGE_SIZE * i; 580145132Sanholt } 581145132Sanholt for ( offset = 0 ; 582145132Sanholt offset + size <= total && entry->buf_count < count ; 583145132Sanholt offset += alignment, ++entry->buf_count ) { 584145132Sanholt buf = &entry->buflist[entry->buf_count]; 585145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 586145132Sanholt buf->total = alignment; 587145132Sanholt buf->order = order; 588145132Sanholt buf->used = 0; 589145132Sanholt buf->offset = (dma->byte_count + byte_count + offset); 590145132Sanholt buf->address = (void *)(vaddr + offset); 591145132Sanholt buf->bus_address = bus_addr + offset; 592145132Sanholt buf->next = NULL; 593145132Sanholt buf->pending = 0; 594145132Sanholt buf->filp = NULL; 595145132Sanholt 596145132Sanholt buf->dev_priv_size = dev->dev_priv_size; 597145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 598145132Sanholt M_NOWAIT | M_ZERO); 599145132Sanholt if (buf->dev_private == NULL) { 600145132Sanholt /* Set count correctly so we free the proper amount. */ 601145132Sanholt entry->buf_count = count; 602145132Sanholt entry->seg_count = count; 603145132Sanholt drm_cleanup_buf_error(dev, entry); 604145132Sanholt free(temp_pagelist, M_DRM); 605145132Sanholt return DRM_ERR(ENOMEM); 606145132Sanholt } 607145132Sanholt 608145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 609145132Sanholt entry->buf_count, buf->address ); 610145132Sanholt } 611145132Sanholt byte_count += PAGE_SIZE << page_order; 612145132Sanholt } 613145132Sanholt 614145132Sanholt temp_buflist = realloc(dma->buflist, 615145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 616145132Sanholt M_NOWAIT); 617145132Sanholt if (temp_buflist == NULL) { 618145132Sanholt /* Free the entry because it isn't valid */ 619145132Sanholt drm_cleanup_buf_error(dev, entry); 620145132Sanholt free(temp_pagelist, M_DRM); 621145132Sanholt return DRM_ERR(ENOMEM); 622145132Sanholt } 623145132Sanholt dma->buflist = temp_buflist; 624145132Sanholt 625145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 626145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 627145132Sanholt } 628145132Sanholt 629145132Sanholt /* No allocations failed, so now we can replace the orginal pagelist 630145132Sanholt * with the new one. 631145132Sanholt */ 632145132Sanholt free(dma->pagelist, M_DRM); 633145132Sanholt dma->pagelist = temp_pagelist; 634145132Sanholt 635145132Sanholt dma->buf_count += entry->buf_count; 636145132Sanholt dma->seg_count += entry->seg_count; 637145132Sanholt dma->page_count += entry->seg_count << page_order; 638145132Sanholt dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 639145132Sanholt 640145132Sanholt request->count = entry->buf_count; 641145132Sanholt request->size = size; 642145132Sanholt 643145132Sanholt return 0; 644145132Sanholt 645145132Sanholt} 646145132Sanholt 647145132Sanholtstatic int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request) 648145132Sanholt{ 649145132Sanholt drm_device_dma_t *dma = dev->dma; 650145132Sanholt drm_buf_entry_t *entry; 651145132Sanholt drm_buf_t *buf; 652145132Sanholt unsigned long offset; 653145132Sanholt unsigned long agp_offset; 654145132Sanholt int count; 655145132Sanholt int order; 656145132Sanholt int size; 657145132Sanholt int alignment; 658145132Sanholt int page_order; 659145132Sanholt int total; 660145132Sanholt int byte_count; 661145132Sanholt int i; 662145132Sanholt drm_buf_t **temp_buflist; 663145132Sanholt 664145132Sanholt count = request->count; 665145132Sanholt order = drm_order(request->size); 666145132Sanholt size = 1 << order; 667145132Sanholt 668145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 669145132Sanholt ? round_page(size) : size; 670145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 671145132Sanholt total = PAGE_SIZE << page_order; 672145132Sanholt 673145132Sanholt byte_count = 0; 674145132Sanholt agp_offset = request->agp_start; 675145132Sanholt 676145132Sanholt DRM_DEBUG( "count: %d\n", count ); 677145132Sanholt DRM_DEBUG( "order: %d\n", order ); 678145132Sanholt DRM_DEBUG( "size: %d\n", size ); 679145132Sanholt DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); 680145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 681145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 682145132Sanholt DRM_DEBUG( "total: %d\n", total ); 683145132Sanholt 684145132Sanholt entry = &dma->bufs[order]; 685145132Sanholt 686145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 687145132Sanholt M_NOWAIT | M_ZERO); 688145132Sanholt if (entry->buflist == NULL) 689145132Sanholt return DRM_ERR(ENOMEM); 690145132Sanholt 691145132Sanholt entry->buf_size = size; 692145132Sanholt entry->page_order = page_order; 693145132Sanholt 694145132Sanholt offset = 0; 695145132Sanholt 696145132Sanholt while ( entry->buf_count < count ) { 697145132Sanholt buf = &entry->buflist[entry->buf_count]; 698145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 699145132Sanholt buf->total = alignment; 700145132Sanholt buf->order = order; 701145132Sanholt buf->used = 0; 702145132Sanholt 703145132Sanholt buf->offset = (dma->byte_count + offset); 704145132Sanholt buf->bus_address = agp_offset + offset; 705145132Sanholt buf->address = (void *)(agp_offset + offset + dev->sg->handle); 706145132Sanholt buf->next = NULL; 707145132Sanholt buf->pending = 0; 708145132Sanholt buf->filp = NULL; 709145132Sanholt 710145132Sanholt buf->dev_priv_size = dev->dev_priv_size; 711145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 712145132Sanholt M_NOWAIT | M_ZERO); 713145132Sanholt if (buf->dev_private == NULL) { 714145132Sanholt /* Set count correctly so we free the proper amount. */ 715145132Sanholt entry->buf_count = count; 716145132Sanholt drm_cleanup_buf_error(dev, entry); 717145132Sanholt return DRM_ERR(ENOMEM); 718145132Sanholt } 719145132Sanholt 720145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 721145132Sanholt entry->buf_count, buf->address ); 722145132Sanholt 723145132Sanholt offset += alignment; 724145132Sanholt entry->buf_count++; 725145132Sanholt byte_count += PAGE_SIZE << page_order; 726145132Sanholt } 727145132Sanholt 728145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 729145132Sanholt 730145132Sanholt temp_buflist = realloc(dma->buflist, 731145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 732145132Sanholt M_NOWAIT); 733145132Sanholt if (temp_buflist == NULL) { 734145132Sanholt /* Free the entry because it isn't valid */ 735145132Sanholt drm_cleanup_buf_error(dev, entry); 736145132Sanholt return DRM_ERR(ENOMEM); 737145132Sanholt } 738145132Sanholt dma->buflist = temp_buflist; 739145132Sanholt 740145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 741145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 742145132Sanholt } 743145132Sanholt 744145132Sanholt dma->buf_count += entry->buf_count; 745145132Sanholt dma->byte_count += byte_count; 746145132Sanholt 747145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 748145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 749145132Sanholt 750145132Sanholt request->count = entry->buf_count; 751145132Sanholt request->size = size; 752145132Sanholt 753145132Sanholt dma->flags = _DRM_DMA_USE_SG; 754145132Sanholt 755145132Sanholt return 0; 756145132Sanholt} 757145132Sanholt 758145132Sanholtint drm_addbufs(DRM_IOCTL_ARGS) 759145132Sanholt{ 760145132Sanholt DRM_DEVICE; 761145132Sanholt drm_buf_desc_t request; 762145132Sanholt int err; 763145132Sanholt int order; 764145132Sanholt 765145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) ); 766145132Sanholt 767145132Sanholt if (request.count < 0 || request.count > 4096) 768145132Sanholt return DRM_ERR(EINVAL); 769145132Sanholt 770145132Sanholt order = drm_order(request.size); 771145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 772145132Sanholt return DRM_ERR(EINVAL); 773145132Sanholt 774145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 775145132Sanholt /* No more allocations after first buffer-using ioctl. */ 776145132Sanholt if (dev->buf_use != 0) { 777145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 778145132Sanholt return DRM_ERR(EBUSY); 779145132Sanholt } 780145132Sanholt /* No more than one allocation per order */ 781145132Sanholt if (dev->dma->bufs[order].buf_count != 0) { 782145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 783145132Sanholt return DRM_ERR(ENOMEM); 784145132Sanholt } 785145132Sanholt 786145132Sanholt if ( request.flags & _DRM_AGP_BUFFER ) 787145132Sanholt err = drm_addbufs_agp(dev, &request); 788145132Sanholt else 789145132Sanholt if ( request.flags & _DRM_SG_BUFFER ) 790145132Sanholt err = drm_addbufs_sg(dev, &request); 791145132Sanholt else 792145132Sanholt err = drm_addbufs_pci(dev, &request); 793145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 794145132Sanholt 795145132Sanholt DRM_COPY_TO_USER_IOCTL((drm_buf_desc_t *)data, request, sizeof(request)); 796145132Sanholt 797145132Sanholt return err; 798145132Sanholt} 799145132Sanholt 800145132Sanholtint drm_infobufs(DRM_IOCTL_ARGS) 801145132Sanholt{ 802145132Sanholt DRM_DEVICE; 803145132Sanholt drm_device_dma_t *dma = dev->dma; 804145132Sanholt drm_buf_info_t request; 805145132Sanholt int i; 806145132Sanholt int count; 807145132Sanholt int retcode = 0; 808145132Sanholt 809145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_info_t *)data, sizeof(request) ); 810145132Sanholt 811145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 812145132Sanholt ++dev->buf_use; /* Can't allocate more after this call */ 813145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 814145132Sanholt 815145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 816145132Sanholt if ( dma->bufs[i].buf_count ) ++count; 817145132Sanholt } 818145132Sanholt 819145132Sanholt DRM_DEBUG( "count = %d\n", count ); 820145132Sanholt 821145132Sanholt if ( request.count >= count ) { 822145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 823145132Sanholt if ( dma->bufs[i].buf_count ) { 824145132Sanholt drm_buf_desc_t from; 825145132Sanholt 826145132Sanholt from.count = dma->bufs[i].buf_count; 827145132Sanholt from.size = dma->bufs[i].buf_size; 828145132Sanholt from.low_mark = dma->bufs[i].freelist.low_mark; 829145132Sanholt from.high_mark = dma->bufs[i].freelist.high_mark; 830145132Sanholt 831145132Sanholt if (DRM_COPY_TO_USER(&request.list[count], &from, 832145132Sanholt sizeof(drm_buf_desc_t)) != 0) { 833145132Sanholt retcode = DRM_ERR(EFAULT); 834145132Sanholt break; 835145132Sanholt } 836145132Sanholt 837145132Sanholt DRM_DEBUG( "%d %d %d %d %d\n", 838145132Sanholt i, 839145132Sanholt dma->bufs[i].buf_count, 840145132Sanholt dma->bufs[i].buf_size, 841145132Sanholt dma->bufs[i].freelist.low_mark, 842145132Sanholt dma->bufs[i].freelist.high_mark ); 843145132Sanholt ++count; 844145132Sanholt } 845145132Sanholt } 846145132Sanholt } 847145132Sanholt request.count = count; 848145132Sanholt 849145132Sanholt DRM_COPY_TO_USER_IOCTL( (drm_buf_info_t *)data, request, sizeof(request) ); 850145132Sanholt 851145132Sanholt return retcode; 852145132Sanholt} 853145132Sanholt 854145132Sanholtint drm_markbufs(DRM_IOCTL_ARGS) 855145132Sanholt{ 856145132Sanholt DRM_DEVICE; 857145132Sanholt drm_device_dma_t *dma = dev->dma; 858145132Sanholt drm_buf_desc_t request; 859145132Sanholt int order; 860145132Sanholt 861145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) ); 862145132Sanholt 863145132Sanholt DRM_DEBUG( "%d, %d, %d\n", 864145132Sanholt request.size, request.low_mark, request.high_mark ); 865145132Sanholt 866145132Sanholt 867145132Sanholt order = drm_order(request.size); 868145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 869145132Sanholt request.low_mark < 0 || request.high_mark < 0) { 870145132Sanholt return DRM_ERR(EINVAL); 871145132Sanholt } 872145132Sanholt 873145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 874145132Sanholt if (request.low_mark > dma->bufs[order].buf_count || 875145132Sanholt request.high_mark > dma->bufs[order].buf_count) { 876145132Sanholt return DRM_ERR(EINVAL); 877145132Sanholt } 878145132Sanholt 879145132Sanholt dma->bufs[order].freelist.low_mark = request.low_mark; 880145132Sanholt dma->bufs[order].freelist.high_mark = request.high_mark; 881145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 882145132Sanholt 883145132Sanholt return 0; 884145132Sanholt} 885145132Sanholt 886145132Sanholtint drm_freebufs(DRM_IOCTL_ARGS) 887145132Sanholt{ 888145132Sanholt DRM_DEVICE; 889145132Sanholt drm_device_dma_t *dma = dev->dma; 890145132Sanholt drm_buf_free_t request; 891145132Sanholt int i; 892145132Sanholt int idx; 893145132Sanholt drm_buf_t *buf; 894145132Sanholt int retcode = 0; 895145132Sanholt 896145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_free_t *)data, sizeof(request) ); 897145132Sanholt 898145132Sanholt DRM_DEBUG( "%d\n", request.count ); 899145132Sanholt 900145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 901145132Sanholt for ( i = 0 ; i < request.count ; i++ ) { 902145132Sanholt if (DRM_COPY_FROM_USER(&idx, &request.list[i], sizeof(idx))) { 903145132Sanholt retcode = DRM_ERR(EFAULT); 904145132Sanholt break; 905145132Sanholt } 906145132Sanholt if ( idx < 0 || idx >= dma->buf_count ) { 907145132Sanholt DRM_ERROR( "Index %d (of %d max)\n", 908145132Sanholt idx, dma->buf_count - 1 ); 909145132Sanholt retcode = DRM_ERR(EINVAL); 910145132Sanholt break; 911145132Sanholt } 912145132Sanholt buf = dma->buflist[idx]; 913145132Sanholt if ( buf->filp != filp ) { 914145132Sanholt DRM_ERROR("Process %d freeing buffer not owned\n", 915145132Sanholt DRM_CURRENTPID); 916145132Sanholt retcode = DRM_ERR(EINVAL); 917145132Sanholt break; 918145132Sanholt } 919145132Sanholt drm_free_buffer(dev, buf); 920145132Sanholt } 921145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 922145132Sanholt 923145132Sanholt return retcode; 924145132Sanholt} 925145132Sanholt 926145132Sanholtint drm_mapbufs(DRM_IOCTL_ARGS) 927145132Sanholt{ 928145132Sanholt DRM_DEVICE; 929145132Sanholt drm_device_dma_t *dma = dev->dma; 930145132Sanholt int retcode = 0; 931145132Sanholt const int zero = 0; 932145132Sanholt vm_offset_t address; 933145132Sanholt struct vmspace *vms; 934145132Sanholt#ifdef __FreeBSD__ 935145132Sanholt vm_ooffset_t foff; 936145132Sanholt vm_size_t size; 937145132Sanholt vm_offset_t vaddr; 938145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 939145132Sanholt struct vnode *vn; 940145132Sanholt vm_size_t size; 941145132Sanholt vaddr_t vaddr; 942145132Sanholt#endif /* __NetBSD__ || __OpenBSD__ */ 943145132Sanholt 944145132Sanholt drm_buf_map_t request; 945145132Sanholt int i; 946145132Sanholt 947145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_map_t *)data, sizeof(request) ); 948145132Sanholt 949145132Sanholt#if defined(__NetBSD__) || defined(__OpenBSD__) 950145132Sanholt if (!vfinddev(kdev, VCHR, &vn)) 951145132Sanholt return 0; /* FIXME: Shouldn't this be EINVAL or something? */ 952145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 953145132Sanholt 954145132Sanholt#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 955145132Sanholt vms = p->td_proc->p_vmspace; 956145132Sanholt#else 957145132Sanholt vms = p->p_vmspace; 958145132Sanholt#endif 959145132Sanholt 960145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 961145132Sanholt dev->buf_use++; /* Can't allocate more after this call */ 962145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 963145132Sanholt 964145132Sanholt if (request.count < dma->buf_count) 965145132Sanholt goto done; 966145132Sanholt 967145132Sanholt if ((dev->use_agp && (dma->flags & _DRM_DMA_USE_AGP)) || 968145132Sanholt (dev->use_sg && (dma->flags & _DRM_DMA_USE_SG))) { 969145132Sanholt drm_local_map_t *map = dev->agp_buffer_map; 970145132Sanholt 971145132Sanholt if (map == NULL) { 972145132Sanholt retcode = EINVAL; 973145132Sanholt goto done; 974145132Sanholt } 975145132Sanholt size = round_page(map->size); 976145132Sanholt foff = map->offset; 977145132Sanholt } else { 978145132Sanholt size = round_page(dma->byte_count), 979145132Sanholt foff = 0; 980145132Sanholt } 981145132Sanholt 982145132Sanholt#ifdef __FreeBSD__ 983145132Sanholt vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 984145132Sanholt#if __FreeBSD_version >= 600023 985145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 986145132Sanholt VM_PROT_ALL, MAP_SHARED, OBJT_DEVICE, kdev, foff ); 987145132Sanholt#else 988145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 989145132Sanholt VM_PROT_ALL, MAP_SHARED, SLIST_FIRST(&kdev->si_hlist), foff ); 990145132Sanholt#endif 991145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 992145132Sanholt vaddr = round_page((vaddr_t)vms->vm_daddr + MAXDSIZ); 993145132Sanholt retcode = uvm_mmap(&vms->vm_map, &vaddr, size, 994145132Sanholt UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED, 995145132Sanholt &vn->v_uobj, foff, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 996145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 997145132Sanholt if (retcode) 998145132Sanholt goto done; 999145132Sanholt 1000145132Sanholt request.virtual = (void *)vaddr; 1001145132Sanholt 1002145132Sanholt for ( i = 0 ; i < dma->buf_count ; i++ ) { 1003145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].idx, 1004145132Sanholt &dma->buflist[i]->idx, sizeof(request.list[0].idx))) { 1005145132Sanholt retcode = EFAULT; 1006145132Sanholt goto done; 1007145132Sanholt } 1008145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].total, 1009145132Sanholt &dma->buflist[i]->total, sizeof(request.list[0].total))) { 1010145132Sanholt retcode = EFAULT; 1011145132Sanholt goto done; 1012145132Sanholt } 1013145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].used, &zero, 1014145132Sanholt sizeof(zero))) { 1015145132Sanholt retcode = EFAULT; 1016145132Sanholt goto done; 1017145132Sanholt } 1018145132Sanholt address = vaddr + dma->buflist[i]->offset; /* *** */ 1019145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].address, &address, 1020145132Sanholt sizeof(address))) { 1021145132Sanholt retcode = EFAULT; 1022145132Sanholt goto done; 1023145132Sanholt } 1024145132Sanholt } 1025145132Sanholt 1026145132Sanholt done: 1027145132Sanholt request.count = dma->buf_count; 1028145132Sanholt 1029145132Sanholt DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode ); 1030145132Sanholt 1031145132Sanholt DRM_COPY_TO_USER_IOCTL((drm_buf_map_t *)data, request, sizeof(request)); 1032145132Sanholt 1033145132Sanholt return DRM_ERR(retcode); 1034145132Sanholt} 1035