drm_bufs.c revision 152909
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 */ 33145132Sanholt 34152909Sanholt#include <sys/cdefs.h> 35152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/drm_bufs.c 152909 2005-11-28 23:13:57Z anholt $"); 36152909Sanholt 37152909Sanholt#include "dev/pci/pcireg.h" 38152909Sanholt 39145132Sanholt#include "dev/drm/drmP.h" 40145132Sanholt 41145132Sanholt/* 42145132Sanholt * Compute order. Can be made faster. 43145132Sanholt */ 44145132Sanholtint drm_order(unsigned long size) 45145132Sanholt{ 46145132Sanholt int order; 47145132Sanholt unsigned long tmp; 48145132Sanholt 49145132Sanholt for ( order = 0, tmp = size ; tmp >>= 1 ; ++order ); 50145132Sanholt 51145132Sanholt if ( size & ~(1 << order) ) 52145132Sanholt ++order; 53145132Sanholt 54145132Sanholt return order; 55145132Sanholt} 56145132Sanholt 57152909Sanholt/* Allocation of PCI memory resources (framebuffer, registers, etc.) for 58152909Sanholt * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 59152909Sanholt * address for accessing them. Cleaned up at unload. 60152909Sanholt */ 61152909Sanholtstatic int drm_alloc_resource(drm_device_t *dev, int resource) 62145132Sanholt{ 63152909Sanholt if (resource >= DRM_MAX_PCI_RESOURCE) { 64152909Sanholt DRM_ERROR("Resource %d too large\n", resource); 65152909Sanholt return 1; 66152909Sanholt } 67145132Sanholt 68152909Sanholt DRM_UNLOCK(); 69152909Sanholt if (dev->pcir[resource] != NULL) { 70152909Sanholt DRM_LOCK(); 71145132Sanholt return 0; 72145132Sanholt } 73145132Sanholt 74152909Sanholt dev->pcirid[resource] = PCIR_BAR(resource); 75152909Sanholt dev->pcir[resource] = bus_alloc_resource_any(dev->device, 76152909Sanholt SYS_RES_MEMORY, &dev->pcirid[resource], RF_SHAREABLE); 77152909Sanholt DRM_LOCK(); 78145132Sanholt 79152909Sanholt if (dev->pcir[resource] == NULL) { 80152909Sanholt DRM_ERROR("Couldn't find resource 0x%x\n", resource); 81152909Sanholt return 1; 82152909Sanholt } 83145132Sanholt 84152909Sanholt return 0; 85145132Sanholt} 86145132Sanholt 87152909Sanholtunsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource) 88145132Sanholt{ 89152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 90152909Sanholt return 0; 91145132Sanholt 92152909Sanholt return rman_get_start(dev->pcir[resource]); 93145132Sanholt} 94145132Sanholt 95152909Sanholtunsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) 96145132Sanholt{ 97152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 98152909Sanholt return 0; 99145132Sanholt 100152909Sanholt return rman_get_size(dev->pcir[resource]); 101145132Sanholt} 102145132Sanholt 103152909Sanholtint drm_addmap(drm_device_t * dev, unsigned long offset, unsigned long size, 104152909Sanholt drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t **map_ptr) 105145132Sanholt{ 106145132Sanholt drm_local_map_t *map; 107152909Sanholt int align; 108152909Sanholt /*drm_agp_mem_t *entry; 109152909Sanholt int valid;*/ 110145132Sanholt 111145132Sanholt /* Only allow shared memory to be removable since we only keep enough 112145132Sanholt * book keeping information about shared memory to allow for removal 113145132Sanholt * when processes fork. 114145132Sanholt */ 115152909Sanholt if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 116152909Sanholt DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 117145132Sanholt return EINVAL; 118152909Sanholt } 119152909Sanholt if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 120152909Sanholt DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 121152909Sanholt offset, size); 122145132Sanholt return EINVAL; 123152909Sanholt } 124152909Sanholt if (offset + size < offset) { 125152909Sanholt DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 126152909Sanholt offset, size); 127145132Sanholt return EINVAL; 128152909Sanholt } 129145132Sanholt 130152909Sanholt DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 131152909Sanholt size, type); 132145132Sanholt 133145132Sanholt /* Check if this is just another version of a kernel-allocated map, and 134145132Sanholt * just hand that back if so. 135145132Sanholt */ 136152909Sanholt if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 137152909Sanholt type == _DRM_SHM) { 138145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 139152909Sanholt if (map->type == type && (map->offset == offset || 140152909Sanholt (map->type == _DRM_SHM && 141152909Sanholt map->flags == _DRM_CONTAINS_LOCK))) { 142152909Sanholt map->size = size; 143152909Sanholt DRM_DEBUG("Found kernel map %d\n", type); 144145132Sanholt goto done; 145145132Sanholt } 146145132Sanholt } 147145132Sanholt } 148152909Sanholt DRM_UNLOCK(); 149145132Sanholt 150145132Sanholt /* Allocate a new map structure, fill it in, and do any type-specific 151145132Sanholt * initialization necessary. 152145132Sanholt */ 153145132Sanholt map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT); 154145132Sanholt if ( !map ) 155145132Sanholt return DRM_ERR(ENOMEM); 156145132Sanholt 157152909Sanholt map->offset = offset; 158152909Sanholt map->size = size; 159152909Sanholt map->type = type; 160152909Sanholt map->flags = flags; 161145132Sanholt 162145132Sanholt switch ( map->type ) { 163145132Sanholt case _DRM_REGISTERS: 164145478Sanholt map->handle = drm_ioremap(dev, map); 165145132Sanholt if (!(map->flags & _DRM_WRITE_COMBINING)) 166145132Sanholt break; 167145132Sanholt /* FALLTHROUGH */ 168145132Sanholt case _DRM_FRAME_BUFFER: 169145132Sanholt if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 170145132Sanholt map->mtrr = 1; 171145132Sanholt break; 172145132Sanholt case _DRM_SHM: 173145132Sanholt map->handle = malloc(map->size, M_DRM, M_NOWAIT); 174145132Sanholt DRM_DEBUG( "%lu %d %p\n", 175145132Sanholt map->size, drm_order(map->size), map->handle ); 176145132Sanholt if ( !map->handle ) { 177145132Sanholt free(map, M_DRM); 178145132Sanholt return DRM_ERR(ENOMEM); 179145132Sanholt } 180145132Sanholt map->offset = (unsigned long)map->handle; 181145132Sanholt if ( map->flags & _DRM_CONTAINS_LOCK ) { 182145132Sanholt /* Prevent a 2nd X Server from creating a 2nd lock */ 183145132Sanholt DRM_LOCK(); 184145132Sanholt if (dev->lock.hw_lock != NULL) { 185145132Sanholt DRM_UNLOCK(); 186145132Sanholt free(map->handle, M_DRM); 187145132Sanholt free(map, M_DRM); 188145132Sanholt return DRM_ERR(EBUSY); 189145132Sanholt } 190145132Sanholt dev->lock.hw_lock = map->handle; /* Pointer to lock */ 191145132Sanholt DRM_UNLOCK(); 192145132Sanholt } 193145132Sanholt break; 194145132Sanholt case _DRM_AGP: 195152909Sanholt /*valid = 0;*/ 196145132Sanholt map->offset += dev->agp->base; 197145132Sanholt map->mtrr = dev->agp->mtrr; /* for getmap */ 198152909Sanholt /*for (entry = dev->agp->memory; entry; entry = entry->next) { 199152909Sanholt if ((map->offset >= entry->bound) && 200152909Sanholt (map->offset + map->size <= 201152909Sanholt entry->bound + entry->pages * PAGE_SIZE)) { 202152909Sanholt valid = 1; 203152909Sanholt break; 204152909Sanholt } 205152909Sanholt } 206152909Sanholt if (!valid) { 207152909Sanholt free(map, M_DRM); 208152909Sanholt return DRM_ERR(EACCES); 209152909Sanholt }*/ 210145132Sanholt break; 211145132Sanholt case _DRM_SCATTER_GATHER: 212145132Sanholt if (!dev->sg) { 213145132Sanholt free(map, M_DRM); 214145132Sanholt return DRM_ERR(EINVAL); 215145132Sanholt } 216145132Sanholt map->offset = map->offset + dev->sg->handle; 217145132Sanholt break; 218145132Sanholt case _DRM_CONSISTENT: 219152909Sanholt /* Unfortunately, we don't get any alignment specification from 220152909Sanholt * the caller, so we have to guess. drm_pci_alloc requires 221152909Sanholt * a power-of-two alignment, so try to align the bus address of 222152909Sanholt * the map to it size if possible, otherwise just assume 223152909Sanholt * PAGE_SIZE alignment. 224152909Sanholt */ 225152909Sanholt align = map->size; 226152909Sanholt if ((align & (align - 1)) != 0) 227152909Sanholt align = PAGE_SIZE; 228152909Sanholt map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 229152909Sanholt if (map->dmah == NULL) { 230145132Sanholt free(map, M_DRM); 231152909Sanholt return DRM_ERR(ENOMEM); 232145132Sanholt } 233152909Sanholt map->handle = map->dmah->vaddr; 234152909Sanholt map->offset = map->dmah->busaddr; 235145132Sanholt break; 236145132Sanholt default: 237152909Sanholt DRM_ERROR("Bad map type %d\n", map->type); 238145132Sanholt free(map, M_DRM); 239145132Sanholt return DRM_ERR(EINVAL); 240145132Sanholt } 241145132Sanholt 242145132Sanholt DRM_LOCK(); 243145132Sanholt TAILQ_INSERT_TAIL(&dev->maplist, map, link); 244145132Sanholt 245145132Sanholtdone: 246145132Sanholt /* Jumped to, with lock held, when a kernel map is found. */ 247152909Sanholt 248152909Sanholt DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 249152909Sanholt map->size); 250152909Sanholt 251152909Sanholt *map_ptr = map; 252152909Sanholt 253152909Sanholt return 0; 254152909Sanholt} 255152909Sanholt 256152909Sanholtint drm_addmap_ioctl(DRM_IOCTL_ARGS) 257152909Sanholt{ 258152909Sanholt drm_map_t request; 259152909Sanholt drm_local_map_t *map; 260152909Sanholt int err; 261152909Sanholt DRM_DEVICE; 262152909Sanholt 263152909Sanholt if (!(dev->flags & (FREAD|FWRITE))) 264152909Sanholt return DRM_ERR(EACCES); /* Require read/write */ 265152909Sanholt 266152909Sanholt DRM_COPY_FROM_USER_IOCTL(request, (drm_map_t *)data, sizeof(drm_map_t)); 267152909Sanholt 268152909Sanholt if (!DRM_SUSER(p) && request.type != _DRM_AGP) 269152909Sanholt return DRM_ERR(EACCES); 270152909Sanholt 271152909Sanholt DRM_LOCK(); 272152909Sanholt err = drm_addmap(dev, request.offset, request.size, request.type, 273152909Sanholt request.flags, &map); 274152909Sanholt DRM_UNLOCK(); 275152909Sanholt if (err != 0) 276152909Sanholt return err; 277152909Sanholt 278145132Sanholt request.offset = map->offset; 279145132Sanholt request.size = map->size; 280145132Sanholt request.type = map->type; 281145132Sanholt request.flags = map->flags; 282145132Sanholt request.mtrr = map->mtrr; 283145132Sanholt request.handle = map->handle; 284145132Sanholt 285152909Sanholt if (request.type != _DRM_SHM) { 286145132Sanholt request.handle = (void *)request.offset; 287145132Sanholt } 288152909Sanholt DRM_COPY_TO_USER_IOCTL((drm_map_t *)data, request, sizeof(drm_map_t)); 289145132Sanholt 290145132Sanholt return 0; 291145132Sanholt} 292145132Sanholt 293152909Sanholtvoid drm_rmmap(drm_device_t *dev, drm_local_map_t *map) 294145132Sanholt{ 295145132Sanholt DRM_SPINLOCK_ASSERT(&dev->dev_lock); 296145132Sanholt 297145132Sanholt TAILQ_REMOVE(&dev->maplist, map, link); 298145132Sanholt 299145132Sanholt switch (map->type) { 300145132Sanholt case _DRM_REGISTERS: 301145132Sanholt if (map->bsr == NULL) 302145132Sanholt drm_ioremapfree(map); 303145132Sanholt /* FALLTHROUGH */ 304145132Sanholt case _DRM_FRAME_BUFFER: 305145132Sanholt if (map->mtrr) { 306145132Sanholt int __unused retcode; 307145132Sanholt 308152909Sanholt retcode = drm_mtrr_del(0, map->offset, map->size, 309145132Sanholt DRM_MTRR_WC); 310145132Sanholt DRM_DEBUG("mtrr_del = %d\n", retcode); 311145132Sanholt } 312145132Sanholt break; 313145132Sanholt case _DRM_SHM: 314145132Sanholt free(map->handle, M_DRM); 315145132Sanholt break; 316145132Sanholt case _DRM_AGP: 317145132Sanholt case _DRM_SCATTER_GATHER: 318145132Sanholt break; 319145132Sanholt case _DRM_CONSISTENT: 320152909Sanholt drm_pci_free(dev, map->dmah); 321145132Sanholt break; 322145132Sanholt } 323145132Sanholt 324145132Sanholt if (map->bsr != NULL) { 325145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 326145132Sanholt map->bsr); 327145132Sanholt } 328145132Sanholt 329145132Sanholt free(map, M_DRM); 330145132Sanholt} 331145132Sanholt 332145132Sanholt/* Remove a map private from list and deallocate resources if the mapping 333145132Sanholt * isn't in use. 334145132Sanholt */ 335145132Sanholt 336152909Sanholtint drm_rmmap_ioctl(DRM_IOCTL_ARGS) 337145132Sanholt{ 338145132Sanholt DRM_DEVICE; 339145132Sanholt drm_local_map_t *map; 340145132Sanholt drm_map_t request; 341145132Sanholt 342145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_map_t *)data, sizeof(request) ); 343145132Sanholt 344145132Sanholt DRM_LOCK(); 345145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 346145132Sanholt if (map->handle == request.handle && 347145132Sanholt map->flags & _DRM_REMOVABLE) 348145132Sanholt break; 349145132Sanholt } 350145132Sanholt 351145132Sanholt /* No match found. */ 352145132Sanholt if (map == NULL) { 353145132Sanholt DRM_UNLOCK(); 354145132Sanholt return DRM_ERR(EINVAL); 355145132Sanholt } 356145132Sanholt 357152909Sanholt drm_rmmap(dev, map); 358145132Sanholt 359145132Sanholt DRM_UNLOCK(); 360145132Sanholt 361145132Sanholt return 0; 362145132Sanholt} 363145132Sanholt 364145132Sanholt 365145132Sanholtstatic void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry) 366145132Sanholt{ 367145132Sanholt int i; 368145132Sanholt 369145132Sanholt if (entry->seg_count) { 370145132Sanholt for (i = 0; i < entry->seg_count; i++) { 371152909Sanholt drm_pci_free(dev, entry->seglist[i]); 372145132Sanholt } 373145132Sanholt free(entry->seglist, M_DRM); 374145132Sanholt 375145132Sanholt entry->seg_count = 0; 376145132Sanholt } 377145132Sanholt 378145132Sanholt if (entry->buf_count) { 379145132Sanholt for (i = 0; i < entry->buf_count; i++) { 380145132Sanholt free(entry->buflist[i].dev_private, M_DRM); 381145132Sanholt } 382145132Sanholt free(entry->buflist, M_DRM); 383145132Sanholt 384145132Sanholt entry->buf_count = 0; 385145132Sanholt } 386145132Sanholt} 387145132Sanholt 388152909Sanholtstatic int drm_do_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request) 389145132Sanholt{ 390145132Sanholt drm_device_dma_t *dma = dev->dma; 391145132Sanholt drm_buf_entry_t *entry; 392152909Sanholt /*drm_agp_mem_t *agp_entry; 393152909Sanholt int valid*/ 394145132Sanholt drm_buf_t *buf; 395145132Sanholt unsigned long offset; 396145132Sanholt unsigned long agp_offset; 397145132Sanholt int count; 398145132Sanholt int order; 399145132Sanholt int size; 400145132Sanholt int alignment; 401145132Sanholt int page_order; 402145132Sanholt int total; 403145132Sanholt int byte_count; 404145132Sanholt int i; 405145132Sanholt drm_buf_t **temp_buflist; 406145132Sanholt 407145132Sanholt count = request->count; 408145132Sanholt order = drm_order(request->size); 409145132Sanholt size = 1 << order; 410145132Sanholt 411145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 412145132Sanholt ? round_page(size) : size; 413145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 414145132Sanholt total = PAGE_SIZE << page_order; 415145132Sanholt 416145132Sanholt byte_count = 0; 417145132Sanholt agp_offset = dev->agp->base + request->agp_start; 418145132Sanholt 419145132Sanholt DRM_DEBUG( "count: %d\n", count ); 420145132Sanholt DRM_DEBUG( "order: %d\n", order ); 421145132Sanholt DRM_DEBUG( "size: %d\n", size ); 422145132Sanholt DRM_DEBUG( "agp_offset: 0x%lx\n", agp_offset ); 423145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 424145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 425145132Sanholt DRM_DEBUG( "total: %d\n", total ); 426145132Sanholt 427152909Sanholt /* Make sure buffers are located in AGP memory that we own */ 428152909Sanholt /* Breaks MGA due to drm_alloc_agp not setting up entries for the 429152909Sanholt * memory. Safe to ignore for now because these ioctls are still 430152909Sanholt * root-only. 431152909Sanholt */ 432152909Sanholt /*valid = 0; 433152909Sanholt for (agp_entry = dev->agp->memory; agp_entry; 434152909Sanholt agp_entry = agp_entry->next) { 435152909Sanholt if ((agp_offset >= agp_entry->bound) && 436152909Sanholt (agp_offset + total * count <= 437152909Sanholt agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 438152909Sanholt valid = 1; 439152909Sanholt break; 440152909Sanholt } 441152909Sanholt } 442152909Sanholt if (!valid) { 443152909Sanholt DRM_DEBUG("zone invalid\n"); 444152909Sanholt return DRM_ERR(EINVAL); 445152909Sanholt }*/ 446152909Sanholt 447145132Sanholt entry = &dma->bufs[order]; 448145132Sanholt 449145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 450145132Sanholt M_NOWAIT | M_ZERO); 451145132Sanholt if ( !entry->buflist ) { 452145132Sanholt return DRM_ERR(ENOMEM); 453145132Sanholt } 454145132Sanholt 455145132Sanholt entry->buf_size = size; 456145132Sanholt entry->page_order = page_order; 457145132Sanholt 458145132Sanholt offset = 0; 459145132Sanholt 460145132Sanholt while ( entry->buf_count < count ) { 461145132Sanholt buf = &entry->buflist[entry->buf_count]; 462145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 463145132Sanholt buf->total = alignment; 464145132Sanholt buf->order = order; 465145132Sanholt buf->used = 0; 466145132Sanholt 467145132Sanholt buf->offset = (dma->byte_count + offset); 468145132Sanholt buf->bus_address = agp_offset + offset; 469145132Sanholt buf->address = (void *)(agp_offset + offset); 470145132Sanholt buf->next = NULL; 471145132Sanholt buf->pending = 0; 472145132Sanholt buf->filp = NULL; 473145132Sanholt 474152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 475145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 476145132Sanholt M_NOWAIT | M_ZERO); 477145132Sanholt if (buf->dev_private == NULL) { 478145132Sanholt /* Set count correctly so we free the proper amount. */ 479145132Sanholt entry->buf_count = count; 480145132Sanholt drm_cleanup_buf_error(dev, entry); 481145132Sanholt return DRM_ERR(ENOMEM); 482145132Sanholt } 483145132Sanholt 484145132Sanholt offset += alignment; 485145132Sanholt entry->buf_count++; 486145132Sanholt byte_count += PAGE_SIZE << page_order; 487145132Sanholt } 488145132Sanholt 489145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 490145132Sanholt 491145132Sanholt temp_buflist = realloc(dma->buflist, 492145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 493145132Sanholt M_NOWAIT); 494145132Sanholt if (temp_buflist == NULL) { 495145132Sanholt /* Free the entry because it isn't valid */ 496145132Sanholt drm_cleanup_buf_error(dev, entry); 497145132Sanholt return DRM_ERR(ENOMEM); 498145132Sanholt } 499145132Sanholt dma->buflist = temp_buflist; 500145132Sanholt 501145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 502145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 503145132Sanholt } 504145132Sanholt 505145132Sanholt dma->buf_count += entry->buf_count; 506145132Sanholt dma->byte_count += byte_count; 507145132Sanholt 508145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 509145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 510145132Sanholt 511145132Sanholt request->count = entry->buf_count; 512145132Sanholt request->size = size; 513145132Sanholt 514145132Sanholt dma->flags = _DRM_DMA_USE_AGP; 515145132Sanholt 516145132Sanholt return 0; 517145132Sanholt} 518145132Sanholt 519152909Sanholtstatic int drm_do_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request) 520145132Sanholt{ 521145132Sanholt drm_device_dma_t *dma = dev->dma; 522145132Sanholt int count; 523145132Sanholt int order; 524145132Sanholt int size; 525145132Sanholt int total; 526145132Sanholt int page_order; 527145132Sanholt drm_buf_entry_t *entry; 528145132Sanholt drm_buf_t *buf; 529145132Sanholt int alignment; 530145132Sanholt unsigned long offset; 531145132Sanholt int i; 532145132Sanholt int byte_count; 533145132Sanholt int page_count; 534145132Sanholt unsigned long *temp_pagelist; 535145132Sanholt drm_buf_t **temp_buflist; 536145132Sanholt 537145132Sanholt count = request->count; 538145132Sanholt order = drm_order(request->size); 539145132Sanholt size = 1 << order; 540145132Sanholt 541145132Sanholt DRM_DEBUG( "count=%d, size=%d (%d), order=%d\n", 542145132Sanholt request->count, request->size, size, order ); 543145132Sanholt 544145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 545145132Sanholt ? round_page(size) : size; 546145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 547145132Sanholt total = PAGE_SIZE << page_order; 548145132Sanholt 549145132Sanholt entry = &dma->bufs[order]; 550145132Sanholt 551145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 552145132Sanholt M_NOWAIT | M_ZERO); 553145132Sanholt entry->seglist = malloc(count * sizeof(*entry->seglist), M_DRM, 554145132Sanholt M_NOWAIT | M_ZERO); 555145132Sanholt 556145132Sanholt /* Keep the original pagelist until we know all the allocations 557145132Sanholt * have succeeded 558145132Sanholt */ 559145132Sanholt temp_pagelist = malloc((dma->page_count + (count << page_order)) * 560145132Sanholt sizeof(*dma->pagelist), M_DRM, M_NOWAIT); 561145132Sanholt 562145132Sanholt if (entry->buflist == NULL || entry->seglist == NULL || 563152909Sanholt temp_pagelist == NULL) { 564145132Sanholt free(entry->buflist, M_DRM); 565145132Sanholt free(entry->seglist, M_DRM); 566145132Sanholt return DRM_ERR(ENOMEM); 567145132Sanholt } 568145132Sanholt 569145132Sanholt memcpy(temp_pagelist, dma->pagelist, dma->page_count * 570145132Sanholt sizeof(*dma->pagelist)); 571145132Sanholt 572145132Sanholt DRM_DEBUG( "pagelist: %d entries\n", 573145132Sanholt dma->page_count + (count << page_order) ); 574145132Sanholt 575145132Sanholt entry->buf_size = size; 576145132Sanholt entry->page_order = page_order; 577145132Sanholt byte_count = 0; 578145132Sanholt page_count = 0; 579145132Sanholt 580145132Sanholt while ( entry->buf_count < count ) { 581152909Sanholt drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 582152909Sanholt 0xfffffffful); 583152909Sanholt if (dmah == NULL) { 584145132Sanholt /* Set count correctly so we free the proper amount. */ 585145132Sanholt entry->buf_count = count; 586145132Sanholt entry->seg_count = count; 587145132Sanholt drm_cleanup_buf_error(dev, entry); 588145132Sanholt free(temp_pagelist, M_DRM); 589145132Sanholt return DRM_ERR(ENOMEM); 590145132Sanholt } 591152909Sanholt 592152909Sanholt entry->seglist[entry->seg_count++] = dmah; 593145132Sanholt for ( i = 0 ; i < (1 << page_order) ; i++ ) { 594152909Sanholt DRM_DEBUG( "page %d @ %p\n", 595145132Sanholt dma->page_count + page_count, 596152909Sanholt (char *)dmah->vaddr + PAGE_SIZE * i ); 597145132Sanholt temp_pagelist[dma->page_count + page_count++] = 598152909Sanholt (long)dmah->vaddr + PAGE_SIZE * i; 599145132Sanholt } 600145132Sanholt for ( offset = 0 ; 601145132Sanholt offset + size <= total && entry->buf_count < count ; 602145132Sanholt offset += alignment, ++entry->buf_count ) { 603145132Sanholt buf = &entry->buflist[entry->buf_count]; 604145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 605145132Sanholt buf->total = alignment; 606145132Sanholt buf->order = order; 607145132Sanholt buf->used = 0; 608145132Sanholt buf->offset = (dma->byte_count + byte_count + offset); 609152909Sanholt buf->address = ((char *)dmah->vaddr + offset); 610152909Sanholt buf->bus_address = dmah->busaddr + offset; 611145132Sanholt buf->next = NULL; 612145132Sanholt buf->pending = 0; 613145132Sanholt buf->filp = NULL; 614145132Sanholt 615152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 616145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 617145132Sanholt M_NOWAIT | M_ZERO); 618145132Sanholt if (buf->dev_private == NULL) { 619145132Sanholt /* Set count correctly so we free the proper amount. */ 620145132Sanholt entry->buf_count = count; 621145132Sanholt entry->seg_count = count; 622145132Sanholt drm_cleanup_buf_error(dev, entry); 623145132Sanholt free(temp_pagelist, M_DRM); 624145132Sanholt return DRM_ERR(ENOMEM); 625145132Sanholt } 626145132Sanholt 627145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 628145132Sanholt entry->buf_count, buf->address ); 629145132Sanholt } 630145132Sanholt byte_count += PAGE_SIZE << page_order; 631145132Sanholt } 632145132Sanholt 633145132Sanholt temp_buflist = realloc(dma->buflist, 634145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 635145132Sanholt M_NOWAIT); 636145132Sanholt if (temp_buflist == NULL) { 637145132Sanholt /* Free the entry because it isn't valid */ 638145132Sanholt drm_cleanup_buf_error(dev, entry); 639145132Sanholt free(temp_pagelist, M_DRM); 640145132Sanholt return DRM_ERR(ENOMEM); 641145132Sanholt } 642145132Sanholt dma->buflist = temp_buflist; 643145132Sanholt 644145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 645145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 646145132Sanholt } 647145132Sanholt 648145132Sanholt /* No allocations failed, so now we can replace the orginal pagelist 649145132Sanholt * with the new one. 650145132Sanholt */ 651145132Sanholt free(dma->pagelist, M_DRM); 652145132Sanholt dma->pagelist = temp_pagelist; 653145132Sanholt 654145132Sanholt dma->buf_count += entry->buf_count; 655145132Sanholt dma->seg_count += entry->seg_count; 656145132Sanholt dma->page_count += entry->seg_count << page_order; 657145132Sanholt dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 658145132Sanholt 659145132Sanholt request->count = entry->buf_count; 660145132Sanholt request->size = size; 661145132Sanholt 662145132Sanholt return 0; 663145132Sanholt 664145132Sanholt} 665145132Sanholt 666152909Sanholtstatic int drm_do_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request) 667145132Sanholt{ 668145132Sanholt drm_device_dma_t *dma = dev->dma; 669145132Sanholt drm_buf_entry_t *entry; 670145132Sanholt drm_buf_t *buf; 671145132Sanholt unsigned long offset; 672145132Sanholt unsigned long agp_offset; 673145132Sanholt int count; 674145132Sanholt int order; 675145132Sanholt int size; 676145132Sanholt int alignment; 677145132Sanholt int page_order; 678145132Sanholt int total; 679145132Sanholt int byte_count; 680145132Sanholt int i; 681145132Sanholt drm_buf_t **temp_buflist; 682145132Sanholt 683145132Sanholt count = request->count; 684145132Sanholt order = drm_order(request->size); 685145132Sanholt size = 1 << order; 686145132Sanholt 687145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 688145132Sanholt ? round_page(size) : size; 689145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 690145132Sanholt total = PAGE_SIZE << page_order; 691145132Sanholt 692145132Sanholt byte_count = 0; 693145132Sanholt agp_offset = request->agp_start; 694145132Sanholt 695145132Sanholt DRM_DEBUG( "count: %d\n", count ); 696145132Sanholt DRM_DEBUG( "order: %d\n", order ); 697145132Sanholt DRM_DEBUG( "size: %d\n", size ); 698145132Sanholt DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); 699145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 700145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 701145132Sanholt DRM_DEBUG( "total: %d\n", total ); 702145132Sanholt 703145132Sanholt entry = &dma->bufs[order]; 704145132Sanholt 705145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 706145132Sanholt M_NOWAIT | M_ZERO); 707145132Sanholt if (entry->buflist == NULL) 708145132Sanholt return DRM_ERR(ENOMEM); 709145132Sanholt 710145132Sanholt entry->buf_size = size; 711145132Sanholt entry->page_order = page_order; 712145132Sanholt 713145132Sanholt offset = 0; 714145132Sanholt 715145132Sanholt while ( entry->buf_count < count ) { 716145132Sanholt buf = &entry->buflist[entry->buf_count]; 717145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 718145132Sanholt buf->total = alignment; 719145132Sanholt buf->order = order; 720145132Sanholt buf->used = 0; 721145132Sanholt 722145132Sanholt buf->offset = (dma->byte_count + offset); 723145132Sanholt buf->bus_address = agp_offset + offset; 724145132Sanholt buf->address = (void *)(agp_offset + offset + dev->sg->handle); 725145132Sanholt buf->next = NULL; 726145132Sanholt buf->pending = 0; 727145132Sanholt buf->filp = NULL; 728145132Sanholt 729152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 730145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 731145132Sanholt M_NOWAIT | M_ZERO); 732145132Sanholt if (buf->dev_private == NULL) { 733145132Sanholt /* Set count correctly so we free the proper amount. */ 734145132Sanholt entry->buf_count = count; 735145132Sanholt drm_cleanup_buf_error(dev, entry); 736145132Sanholt return DRM_ERR(ENOMEM); 737145132Sanholt } 738145132Sanholt 739145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 740145132Sanholt entry->buf_count, buf->address ); 741145132Sanholt 742145132Sanholt offset += alignment; 743145132Sanholt entry->buf_count++; 744145132Sanholt byte_count += PAGE_SIZE << page_order; 745145132Sanholt } 746145132Sanholt 747145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 748145132Sanholt 749145132Sanholt temp_buflist = realloc(dma->buflist, 750145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 751145132Sanholt M_NOWAIT); 752145132Sanholt if (temp_buflist == NULL) { 753145132Sanholt /* Free the entry because it isn't valid */ 754145132Sanholt drm_cleanup_buf_error(dev, entry); 755145132Sanholt return DRM_ERR(ENOMEM); 756145132Sanholt } 757145132Sanholt dma->buflist = temp_buflist; 758145132Sanholt 759145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 760145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 761145132Sanholt } 762145132Sanholt 763145132Sanholt dma->buf_count += entry->buf_count; 764145132Sanholt dma->byte_count += byte_count; 765145132Sanholt 766145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 767145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 768145132Sanholt 769145132Sanholt request->count = entry->buf_count; 770145132Sanholt request->size = size; 771145132Sanholt 772145132Sanholt dma->flags = _DRM_DMA_USE_SG; 773145132Sanholt 774145132Sanholt return 0; 775145132Sanholt} 776145132Sanholt 777152909Sanholtint drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request) 778145132Sanholt{ 779152909Sanholt int order, ret; 780145132Sanholt 781152909Sanholt DRM_SPINLOCK(&dev->dma_lock); 782145132Sanholt 783152909Sanholt if (request->count < 0 || request->count > 4096) 784145132Sanholt return DRM_ERR(EINVAL); 785152909Sanholt 786152909Sanholt order = drm_order(request->size); 787152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 788152909Sanholt return DRM_ERR(EINVAL); 789145132Sanholt 790152909Sanholt /* No more allocations after first buffer-using ioctl. */ 791152909Sanholt if (dev->buf_use != 0) { 792152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 793152909Sanholt return DRM_ERR(EBUSY); 794152909Sanholt } 795152909Sanholt /* No more than one allocation per order */ 796152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 797152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 798152909Sanholt return DRM_ERR(ENOMEM); 799152909Sanholt } 800152909Sanholt 801152909Sanholt ret = drm_do_addbufs_agp(dev, request); 802152909Sanholt 803152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 804152909Sanholt 805152909Sanholt return ret; 806152909Sanholt} 807152909Sanholt 808152909Sanholtint drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request) 809152909Sanholt{ 810152909Sanholt int order, ret; 811152909Sanholt 812152909Sanholt DRM_SPINLOCK(&dev->dma_lock); 813152909Sanholt 814152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 815152909Sanholt return DRM_ERR(EACCES); 816152909Sanholt 817152909Sanholt if (request->count < 0 || request->count > 4096) 818152909Sanholt return DRM_ERR(EINVAL); 819152909Sanholt 820152909Sanholt order = drm_order(request->size); 821145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 822145132Sanholt return DRM_ERR(EINVAL); 823145132Sanholt 824152909Sanholt /* No more allocations after first buffer-using ioctl. */ 825152909Sanholt if (dev->buf_use != 0) { 826152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 827152909Sanholt return DRM_ERR(EBUSY); 828152909Sanholt } 829152909Sanholt /* No more than one allocation per order */ 830152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 831152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 832152909Sanholt return DRM_ERR(ENOMEM); 833152909Sanholt } 834152909Sanholt 835152909Sanholt ret = drm_do_addbufs_sg(dev, request); 836152909Sanholt 837152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 838152909Sanholt 839152909Sanholt return ret; 840152909Sanholt} 841152909Sanholt 842152909Sanholtint drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request) 843152909Sanholt{ 844152909Sanholt int order, ret; 845152909Sanholt 846145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 847152909Sanholt 848152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 849152909Sanholt return DRM_ERR(EACCES); 850152909Sanholt 851152909Sanholt if (request->count < 0 || request->count > 4096) 852152909Sanholt return DRM_ERR(EINVAL); 853152909Sanholt 854152909Sanholt order = drm_order(request->size); 855152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 856152909Sanholt return DRM_ERR(EINVAL); 857152909Sanholt 858145132Sanholt /* No more allocations after first buffer-using ioctl. */ 859145132Sanholt if (dev->buf_use != 0) { 860145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 861145132Sanholt return DRM_ERR(EBUSY); 862145132Sanholt } 863145132Sanholt /* No more than one allocation per order */ 864145132Sanholt if (dev->dma->bufs[order].buf_count != 0) { 865145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 866145132Sanholt return DRM_ERR(ENOMEM); 867145132Sanholt } 868145132Sanholt 869152909Sanholt ret = drm_do_addbufs_pci(dev, request); 870152909Sanholt 871152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 872152909Sanholt 873152909Sanholt return ret; 874152909Sanholt} 875152909Sanholt 876152909Sanholtint drm_addbufs_ioctl(DRM_IOCTL_ARGS) 877152909Sanholt{ 878152909Sanholt DRM_DEVICE; 879152909Sanholt drm_buf_desc_t request; 880152909Sanholt int err; 881152909Sanholt 882152909Sanholt DRM_COPY_FROM_USER_IOCTL(request, (drm_buf_desc_t *)data, 883152909Sanholt sizeof(request)); 884152909Sanholt 885152909Sanholt if (request.flags & _DRM_AGP_BUFFER) 886145132Sanholt err = drm_addbufs_agp(dev, &request); 887152909Sanholt else if (request.flags & _DRM_SG_BUFFER) 888145132Sanholt err = drm_addbufs_sg(dev, &request); 889145132Sanholt else 890145132Sanholt err = drm_addbufs_pci(dev, &request); 891145132Sanholt 892152909Sanholt DRM_COPY_TO_USER_IOCTL((drm_buf_desc_t *)data, request, 893152909Sanholt sizeof(request)); 894145132Sanholt 895145132Sanholt return err; 896145132Sanholt} 897145132Sanholt 898145132Sanholtint drm_infobufs(DRM_IOCTL_ARGS) 899145132Sanholt{ 900145132Sanholt DRM_DEVICE; 901145132Sanholt drm_device_dma_t *dma = dev->dma; 902145132Sanholt drm_buf_info_t request; 903145132Sanholt int i; 904145132Sanholt int count; 905145132Sanholt int retcode = 0; 906145132Sanholt 907145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_info_t *)data, sizeof(request) ); 908145132Sanholt 909145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 910145132Sanholt ++dev->buf_use; /* Can't allocate more after this call */ 911145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 912145132Sanholt 913145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 914145132Sanholt if ( dma->bufs[i].buf_count ) ++count; 915145132Sanholt } 916145132Sanholt 917145132Sanholt DRM_DEBUG( "count = %d\n", count ); 918145132Sanholt 919145132Sanholt if ( request.count >= count ) { 920145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 921145132Sanholt if ( dma->bufs[i].buf_count ) { 922145132Sanholt drm_buf_desc_t from; 923145132Sanholt 924145132Sanholt from.count = dma->bufs[i].buf_count; 925145132Sanholt from.size = dma->bufs[i].buf_size; 926145132Sanholt from.low_mark = dma->bufs[i].freelist.low_mark; 927145132Sanholt from.high_mark = dma->bufs[i].freelist.high_mark; 928145132Sanholt 929145132Sanholt if (DRM_COPY_TO_USER(&request.list[count], &from, 930145132Sanholt sizeof(drm_buf_desc_t)) != 0) { 931145132Sanholt retcode = DRM_ERR(EFAULT); 932145132Sanholt break; 933145132Sanholt } 934145132Sanholt 935145132Sanholt DRM_DEBUG( "%d %d %d %d %d\n", 936145132Sanholt i, 937145132Sanholt dma->bufs[i].buf_count, 938145132Sanholt dma->bufs[i].buf_size, 939145132Sanholt dma->bufs[i].freelist.low_mark, 940145132Sanholt dma->bufs[i].freelist.high_mark ); 941145132Sanholt ++count; 942145132Sanholt } 943145132Sanholt } 944145132Sanholt } 945145132Sanholt request.count = count; 946145132Sanholt 947145132Sanholt DRM_COPY_TO_USER_IOCTL( (drm_buf_info_t *)data, request, sizeof(request) ); 948145132Sanholt 949145132Sanholt return retcode; 950145132Sanholt} 951145132Sanholt 952145132Sanholtint drm_markbufs(DRM_IOCTL_ARGS) 953145132Sanholt{ 954145132Sanholt DRM_DEVICE; 955145132Sanholt drm_device_dma_t *dma = dev->dma; 956145132Sanholt drm_buf_desc_t request; 957145132Sanholt int order; 958145132Sanholt 959145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_desc_t *)data, sizeof(request) ); 960145132Sanholt 961145132Sanholt DRM_DEBUG( "%d, %d, %d\n", 962145132Sanholt request.size, request.low_mark, request.high_mark ); 963145132Sanholt 964145132Sanholt 965145132Sanholt order = drm_order(request.size); 966145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 967145132Sanholt request.low_mark < 0 || request.high_mark < 0) { 968145132Sanholt return DRM_ERR(EINVAL); 969145132Sanholt } 970145132Sanholt 971145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 972145132Sanholt if (request.low_mark > dma->bufs[order].buf_count || 973145132Sanholt request.high_mark > dma->bufs[order].buf_count) { 974145132Sanholt return DRM_ERR(EINVAL); 975145132Sanholt } 976145132Sanholt 977145132Sanholt dma->bufs[order].freelist.low_mark = request.low_mark; 978145132Sanholt dma->bufs[order].freelist.high_mark = request.high_mark; 979145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 980145132Sanholt 981145132Sanholt return 0; 982145132Sanholt} 983145132Sanholt 984145132Sanholtint drm_freebufs(DRM_IOCTL_ARGS) 985145132Sanholt{ 986145132Sanholt DRM_DEVICE; 987145132Sanholt drm_device_dma_t *dma = dev->dma; 988145132Sanholt drm_buf_free_t request; 989145132Sanholt int i; 990145132Sanholt int idx; 991145132Sanholt drm_buf_t *buf; 992145132Sanholt int retcode = 0; 993145132Sanholt 994145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_free_t *)data, sizeof(request) ); 995145132Sanholt 996145132Sanholt DRM_DEBUG( "%d\n", request.count ); 997145132Sanholt 998145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 999145132Sanholt for ( i = 0 ; i < request.count ; i++ ) { 1000145132Sanholt if (DRM_COPY_FROM_USER(&idx, &request.list[i], sizeof(idx))) { 1001145132Sanholt retcode = DRM_ERR(EFAULT); 1002145132Sanholt break; 1003145132Sanholt } 1004145132Sanholt if ( idx < 0 || idx >= dma->buf_count ) { 1005145132Sanholt DRM_ERROR( "Index %d (of %d max)\n", 1006145132Sanholt idx, dma->buf_count - 1 ); 1007145132Sanholt retcode = DRM_ERR(EINVAL); 1008145132Sanholt break; 1009145132Sanholt } 1010145132Sanholt buf = dma->buflist[idx]; 1011145132Sanholt if ( buf->filp != filp ) { 1012145132Sanholt DRM_ERROR("Process %d freeing buffer not owned\n", 1013145132Sanholt DRM_CURRENTPID); 1014145132Sanholt retcode = DRM_ERR(EINVAL); 1015145132Sanholt break; 1016145132Sanholt } 1017145132Sanholt drm_free_buffer(dev, buf); 1018145132Sanholt } 1019145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1020145132Sanholt 1021145132Sanholt return retcode; 1022145132Sanholt} 1023145132Sanholt 1024145132Sanholtint drm_mapbufs(DRM_IOCTL_ARGS) 1025145132Sanholt{ 1026145132Sanholt DRM_DEVICE; 1027145132Sanholt drm_device_dma_t *dma = dev->dma; 1028145132Sanholt int retcode = 0; 1029145132Sanholt const int zero = 0; 1030145132Sanholt vm_offset_t address; 1031145132Sanholt struct vmspace *vms; 1032145132Sanholt#ifdef __FreeBSD__ 1033145132Sanholt vm_ooffset_t foff; 1034145132Sanholt vm_size_t size; 1035145132Sanholt vm_offset_t vaddr; 1036145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 1037145132Sanholt struct vnode *vn; 1038152909Sanholt voff_t foff; 1039152909Sanholt vsize_t size; 1040145132Sanholt vaddr_t vaddr; 1041145132Sanholt#endif /* __NetBSD__ || __OpenBSD__ */ 1042145132Sanholt 1043145132Sanholt drm_buf_map_t request; 1044145132Sanholt int i; 1045145132Sanholt 1046145132Sanholt DRM_COPY_FROM_USER_IOCTL( request, (drm_buf_map_t *)data, sizeof(request) ); 1047145132Sanholt 1048145132Sanholt#if defined(__NetBSD__) || defined(__OpenBSD__) 1049145132Sanholt if (!vfinddev(kdev, VCHR, &vn)) 1050145132Sanholt return 0; /* FIXME: Shouldn't this be EINVAL or something? */ 1051145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 1052145132Sanholt 1053145132Sanholt#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1054145132Sanholt vms = p->td_proc->p_vmspace; 1055145132Sanholt#else 1056145132Sanholt vms = p->p_vmspace; 1057145132Sanholt#endif 1058145132Sanholt 1059145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 1060145132Sanholt dev->buf_use++; /* Can't allocate more after this call */ 1061145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1062145132Sanholt 1063145132Sanholt if (request.count < dma->buf_count) 1064145132Sanholt goto done; 1065145132Sanholt 1066152909Sanholt if ((dev->driver.use_agp && (dma->flags & _DRM_DMA_USE_AGP)) || 1067152909Sanholt (dev->driver.use_sg && (dma->flags & _DRM_DMA_USE_SG))) { 1068145132Sanholt drm_local_map_t *map = dev->agp_buffer_map; 1069145132Sanholt 1070145132Sanholt if (map == NULL) { 1071145132Sanholt retcode = EINVAL; 1072145132Sanholt goto done; 1073145132Sanholt } 1074145132Sanholt size = round_page(map->size); 1075145132Sanholt foff = map->offset; 1076145132Sanholt } else { 1077145132Sanholt size = round_page(dma->byte_count), 1078145132Sanholt foff = 0; 1079145132Sanholt } 1080145132Sanholt 1081145132Sanholt#ifdef __FreeBSD__ 1082145132Sanholt vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1083145132Sanholt#if __FreeBSD_version >= 600023 1084145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1085145132Sanholt VM_PROT_ALL, MAP_SHARED, OBJT_DEVICE, kdev, foff ); 1086145132Sanholt#else 1087145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1088145132Sanholt VM_PROT_ALL, MAP_SHARED, SLIST_FIRST(&kdev->si_hlist), foff ); 1089145132Sanholt#endif 1090145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 1091145132Sanholt vaddr = round_page((vaddr_t)vms->vm_daddr + MAXDSIZ); 1092145132Sanholt retcode = uvm_mmap(&vms->vm_map, &vaddr, size, 1093145132Sanholt UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED, 1094145132Sanholt &vn->v_uobj, foff, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 1095145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 1096145132Sanholt if (retcode) 1097145132Sanholt goto done; 1098145132Sanholt 1099145132Sanholt request.virtual = (void *)vaddr; 1100145132Sanholt 1101145132Sanholt for ( i = 0 ; i < dma->buf_count ; i++ ) { 1102145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].idx, 1103145132Sanholt &dma->buflist[i]->idx, sizeof(request.list[0].idx))) { 1104145132Sanholt retcode = EFAULT; 1105145132Sanholt goto done; 1106145132Sanholt } 1107145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].total, 1108145132Sanholt &dma->buflist[i]->total, sizeof(request.list[0].total))) { 1109145132Sanholt retcode = EFAULT; 1110145132Sanholt goto done; 1111145132Sanholt } 1112145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].used, &zero, 1113145132Sanholt sizeof(zero))) { 1114145132Sanholt retcode = EFAULT; 1115145132Sanholt goto done; 1116145132Sanholt } 1117145132Sanholt address = vaddr + dma->buflist[i]->offset; /* *** */ 1118145132Sanholt if (DRM_COPY_TO_USER(&request.list[i].address, &address, 1119145132Sanholt sizeof(address))) { 1120145132Sanholt retcode = EFAULT; 1121145132Sanholt goto done; 1122145132Sanholt } 1123145132Sanholt } 1124145132Sanholt 1125145132Sanholt done: 1126145132Sanholt request.count = dma->buf_count; 1127145132Sanholt 1128145132Sanholt DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode ); 1129145132Sanholt 1130145132Sanholt DRM_COPY_TO_USER_IOCTL((drm_buf_map_t *)data, request, sizeof(request)); 1131145132Sanholt 1132145132Sanholt return DRM_ERR(retcode); 1133145132Sanholt} 1134