drm_bufs.c revision 182080
1145132Sanholt/*- 2145132Sanholt * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 3145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 4145132Sanholt * All Rights Reserved. 5145132Sanholt * 6145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 7145132Sanholt * copy of this software and associated documentation files (the "Software"), 8145132Sanholt * to deal in the Software without restriction, including without limitation 9145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 11145132Sanholt * Software is furnished to do so, subject to the following conditions: 12145132Sanholt * 13145132Sanholt * The above copyright notice and this permission notice (including the next 14145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 15145132Sanholt * Software. 16145132Sanholt * 17145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20145132Sanholt * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23145132Sanholt * OTHER DEALINGS IN THE SOFTWARE. 24145132Sanholt * 25145132Sanholt * Authors: 26145132Sanholt * Rickard E. (Rik) Faith <faith@valinux.com> 27145132Sanholt * Gareth Hughes <gareth@valinux.com> 28145132Sanholt * 29145132Sanholt */ 30145132Sanholt 31152909Sanholt#include <sys/cdefs.h> 32152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/drm_bufs.c 182080 2008-08-23 20:59:12Z rnoland $"); 33152909Sanholt 34182080Srnoland/** @file drm_bufs.c 35182080Srnoland * Implementation of the ioctls for setup of DRM mappings and DMA buffers. 36182080Srnoland */ 37182080Srnoland 38152909Sanholt#include "dev/pci/pcireg.h" 39152909Sanholt 40145132Sanholt#include "dev/drm/drmP.h" 41145132Sanholt 42145132Sanholt/* 43145132Sanholt * Compute order. Can be made faster. 44145132Sanholt */ 45145132Sanholtint drm_order(unsigned long size) 46145132Sanholt{ 47145132Sanholt int order; 48145132Sanholt unsigned long tmp; 49145132Sanholt 50145132Sanholt for ( order = 0, tmp = size ; tmp >>= 1 ; ++order ); 51145132Sanholt 52145132Sanholt if ( size & ~(1 << order) ) 53145132Sanholt ++order; 54145132Sanholt 55145132Sanholt return order; 56145132Sanholt} 57145132Sanholt 58152909Sanholt/* Allocation of PCI memory resources (framebuffer, registers, etc.) for 59152909Sanholt * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 60152909Sanholt * address for accessing them. Cleaned up at unload. 61152909Sanholt */ 62182080Srnolandstatic int drm_alloc_resource(struct drm_device *dev, int resource) 63145132Sanholt{ 64152909Sanholt if (resource >= DRM_MAX_PCI_RESOURCE) { 65152909Sanholt DRM_ERROR("Resource %d too large\n", resource); 66152909Sanholt return 1; 67152909Sanholt } 68145132Sanholt 69152909Sanholt DRM_UNLOCK(); 70152909Sanholt if (dev->pcir[resource] != NULL) { 71152909Sanholt DRM_LOCK(); 72145132Sanholt return 0; 73145132Sanholt } 74145132Sanholt 75152909Sanholt dev->pcirid[resource] = PCIR_BAR(resource); 76152909Sanholt dev->pcir[resource] = bus_alloc_resource_any(dev->device, 77152909Sanholt SYS_RES_MEMORY, &dev->pcirid[resource], RF_SHAREABLE); 78152909Sanholt DRM_LOCK(); 79145132Sanholt 80152909Sanholt if (dev->pcir[resource] == NULL) { 81152909Sanholt DRM_ERROR("Couldn't find resource 0x%x\n", resource); 82152909Sanholt return 1; 83152909Sanholt } 84145132Sanholt 85152909Sanholt return 0; 86145132Sanholt} 87145132Sanholt 88182080Srnolandunsigned long drm_get_resource_start(struct drm_device *dev, 89182080Srnoland unsigned int resource) 90145132Sanholt{ 91152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 92152909Sanholt return 0; 93145132Sanholt 94152909Sanholt return rman_get_start(dev->pcir[resource]); 95145132Sanholt} 96145132Sanholt 97182080Srnolandunsigned long drm_get_resource_len(struct drm_device *dev, 98182080Srnoland unsigned int resource) 99145132Sanholt{ 100152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 101152909Sanholt return 0; 102145132Sanholt 103152909Sanholt return rman_get_size(dev->pcir[resource]); 104145132Sanholt} 105145132Sanholt 106182080Srnolandint drm_addmap(struct drm_device * dev, unsigned long offset, 107182080Srnoland unsigned long size, 108152909Sanholt drm_map_type_t type, drm_map_flags_t flags, drm_local_map_t **map_ptr) 109145132Sanholt{ 110145132Sanholt drm_local_map_t *map; 111152909Sanholt int align; 112152909Sanholt /*drm_agp_mem_t *entry; 113152909Sanholt int valid;*/ 114145132Sanholt 115145132Sanholt /* Only allow shared memory to be removable since we only keep enough 116145132Sanholt * book keeping information about shared memory to allow for removal 117145132Sanholt * when processes fork. 118145132Sanholt */ 119152909Sanholt if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 120152909Sanholt DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 121145132Sanholt return EINVAL; 122152909Sanholt } 123152909Sanholt if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 124152909Sanholt DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 125152909Sanholt offset, size); 126145132Sanholt return EINVAL; 127152909Sanholt } 128152909Sanholt if (offset + size < offset) { 129152909Sanholt DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 130152909Sanholt offset, size); 131145132Sanholt return EINVAL; 132152909Sanholt } 133145132Sanholt 134152909Sanholt DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 135152909Sanholt size, type); 136145132Sanholt 137145132Sanholt /* Check if this is just another version of a kernel-allocated map, and 138145132Sanholt * just hand that back if so. 139145132Sanholt */ 140152909Sanholt if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 141152909Sanholt type == _DRM_SHM) { 142145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 143152909Sanholt if (map->type == type && (map->offset == offset || 144152909Sanholt (map->type == _DRM_SHM && 145152909Sanholt map->flags == _DRM_CONTAINS_LOCK))) { 146152909Sanholt map->size = size; 147152909Sanholt DRM_DEBUG("Found kernel map %d\n", type); 148145132Sanholt goto done; 149145132Sanholt } 150145132Sanholt } 151145132Sanholt } 152152909Sanholt DRM_UNLOCK(); 153145132Sanholt 154145132Sanholt /* Allocate a new map structure, fill it in, and do any type-specific 155145132Sanholt * initialization necessary. 156145132Sanholt */ 157145132Sanholt map = malloc(sizeof(*map), M_DRM, M_ZERO | M_NOWAIT); 158182080Srnoland if ( !map ) { 159182080Srnoland DRM_LOCK(); 160182080Srnoland return ENOMEM; 161182080Srnoland } 162145132Sanholt 163152909Sanholt map->offset = offset; 164152909Sanholt map->size = size; 165152909Sanholt map->type = type; 166152909Sanholt map->flags = flags; 167145132Sanholt 168145132Sanholt switch ( map->type ) { 169145132Sanholt case _DRM_REGISTERS: 170145478Sanholt map->handle = drm_ioremap(dev, map); 171145132Sanholt if (!(map->flags & _DRM_WRITE_COMBINING)) 172145132Sanholt break; 173145132Sanholt /* FALLTHROUGH */ 174145132Sanholt case _DRM_FRAME_BUFFER: 175145132Sanholt if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 176145132Sanholt map->mtrr = 1; 177145132Sanholt break; 178145132Sanholt case _DRM_SHM: 179145132Sanholt map->handle = malloc(map->size, M_DRM, M_NOWAIT); 180145132Sanholt DRM_DEBUG( "%lu %d %p\n", 181145132Sanholt map->size, drm_order(map->size), map->handle ); 182145132Sanholt if ( !map->handle ) { 183145132Sanholt free(map, M_DRM); 184182080Srnoland DRM_LOCK(); 185182080Srnoland return ENOMEM; 186145132Sanholt } 187145132Sanholt map->offset = (unsigned long)map->handle; 188145132Sanholt if ( map->flags & _DRM_CONTAINS_LOCK ) { 189145132Sanholt /* Prevent a 2nd X Server from creating a 2nd lock */ 190145132Sanholt DRM_LOCK(); 191145132Sanholt if (dev->lock.hw_lock != NULL) { 192145132Sanholt DRM_UNLOCK(); 193145132Sanholt free(map->handle, M_DRM); 194145132Sanholt free(map, M_DRM); 195182080Srnoland return EBUSY; 196145132Sanholt } 197145132Sanholt dev->lock.hw_lock = map->handle; /* Pointer to lock */ 198145132Sanholt DRM_UNLOCK(); 199145132Sanholt } 200145132Sanholt break; 201145132Sanholt case _DRM_AGP: 202152909Sanholt /*valid = 0;*/ 203182080Srnoland /* In some cases (i810 driver), user space may have already 204182080Srnoland * added the AGP base itself, because dev->agp->base previously 205182080Srnoland * only got set during AGP enable. So, only add the base 206182080Srnoland * address if the map's offset isn't already within the 207182080Srnoland * aperture. 208182080Srnoland */ 209182080Srnoland if (map->offset < dev->agp->base || 210182080Srnoland map->offset > dev->agp->base + 211182080Srnoland dev->agp->info.ai_aperture_size - 1) { 212182080Srnoland map->offset += dev->agp->base; 213182080Srnoland } 214145132Sanholt map->mtrr = dev->agp->mtrr; /* for getmap */ 215152909Sanholt /*for (entry = dev->agp->memory; entry; entry = entry->next) { 216152909Sanholt if ((map->offset >= entry->bound) && 217152909Sanholt (map->offset + map->size <= 218152909Sanholt entry->bound + entry->pages * PAGE_SIZE)) { 219152909Sanholt valid = 1; 220152909Sanholt break; 221152909Sanholt } 222152909Sanholt } 223152909Sanholt if (!valid) { 224152909Sanholt free(map, M_DRM); 225182080Srnoland DRM_LOCK(); 226182080Srnoland return EACCES; 227152909Sanholt }*/ 228145132Sanholt break; 229145132Sanholt case _DRM_SCATTER_GATHER: 230145132Sanholt if (!dev->sg) { 231145132Sanholt free(map, M_DRM); 232182080Srnoland DRM_LOCK(); 233182080Srnoland return EINVAL; 234145132Sanholt } 235145132Sanholt map->offset = map->offset + dev->sg->handle; 236145132Sanholt break; 237145132Sanholt case _DRM_CONSISTENT: 238152909Sanholt /* Unfortunately, we don't get any alignment specification from 239152909Sanholt * the caller, so we have to guess. drm_pci_alloc requires 240152909Sanholt * a power-of-two alignment, so try to align the bus address of 241152909Sanholt * the map to it size if possible, otherwise just assume 242152909Sanholt * PAGE_SIZE alignment. 243152909Sanholt */ 244152909Sanholt align = map->size; 245152909Sanholt if ((align & (align - 1)) != 0) 246152909Sanholt align = PAGE_SIZE; 247152909Sanholt map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 248152909Sanholt if (map->dmah == NULL) { 249145132Sanholt free(map, M_DRM); 250182080Srnoland DRM_LOCK(); 251182080Srnoland return ENOMEM; 252145132Sanholt } 253152909Sanholt map->handle = map->dmah->vaddr; 254152909Sanholt map->offset = map->dmah->busaddr; 255145132Sanholt break; 256145132Sanholt default: 257152909Sanholt DRM_ERROR("Bad map type %d\n", map->type); 258145132Sanholt free(map, M_DRM); 259182080Srnoland DRM_LOCK(); 260182080Srnoland return 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. */ 268152909Sanholt 269152909Sanholt DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 270152909Sanholt map->size); 271152909Sanholt 272152909Sanholt *map_ptr = map; 273152909Sanholt 274152909Sanholt return 0; 275152909Sanholt} 276152909Sanholt 277182080Srnolandint drm_addmap_ioctl(struct drm_device *dev, void *data, 278182080Srnoland struct drm_file *file_priv) 279152909Sanholt{ 280182080Srnoland drm_map_t *request = data; 281152909Sanholt drm_local_map_t *map; 282152909Sanholt int err; 283152909Sanholt 284152909Sanholt if (!(dev->flags & (FREAD|FWRITE))) 285182080Srnoland return EACCES; /* Require read/write */ 286152909Sanholt 287182080Srnoland if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) 288182080Srnoland return EACCES; 289152909Sanholt 290152909Sanholt DRM_LOCK(); 291182080Srnoland err = drm_addmap(dev, request->offset, request->size, request->type, 292182080Srnoland request->flags, &map); 293152909Sanholt DRM_UNLOCK(); 294152909Sanholt if (err != 0) 295152909Sanholt return err; 296152909Sanholt 297182080Srnoland request->offset = map->offset; 298182080Srnoland request->size = map->size; 299182080Srnoland request->type = map->type; 300182080Srnoland request->flags = map->flags; 301182080Srnoland request->mtrr = map->mtrr; 302182080Srnoland request->handle = map->handle; 303145132Sanholt 304182080Srnoland if (request->type != _DRM_SHM) { 305182080Srnoland request->handle = (void *)request->offset; 306145132Sanholt } 307145132Sanholt 308145132Sanholt return 0; 309145132Sanholt} 310145132Sanholt 311182080Srnolandvoid drm_rmmap(struct drm_device *dev, drm_local_map_t *map) 312145132Sanholt{ 313145132Sanholt DRM_SPINLOCK_ASSERT(&dev->dev_lock); 314145132Sanholt 315145132Sanholt TAILQ_REMOVE(&dev->maplist, map, link); 316145132Sanholt 317145132Sanholt switch (map->type) { 318145132Sanholt case _DRM_REGISTERS: 319145132Sanholt if (map->bsr == NULL) 320145132Sanholt drm_ioremapfree(map); 321145132Sanholt /* FALLTHROUGH */ 322145132Sanholt case _DRM_FRAME_BUFFER: 323145132Sanholt if (map->mtrr) { 324145132Sanholt int __unused retcode; 325145132Sanholt 326152909Sanholt retcode = drm_mtrr_del(0, map->offset, map->size, 327145132Sanholt DRM_MTRR_WC); 328145132Sanholt DRM_DEBUG("mtrr_del = %d\n", retcode); 329145132Sanholt } 330145132Sanholt break; 331145132Sanholt case _DRM_SHM: 332145132Sanholt free(map->handle, M_DRM); 333145132Sanholt break; 334145132Sanholt case _DRM_AGP: 335145132Sanholt case _DRM_SCATTER_GATHER: 336145132Sanholt break; 337145132Sanholt case _DRM_CONSISTENT: 338152909Sanholt drm_pci_free(dev, map->dmah); 339145132Sanholt break; 340182080Srnoland default: 341182080Srnoland DRM_ERROR("Bad map type %d\n", map->type); 342182080Srnoland break; 343145132Sanholt } 344145132Sanholt 345145132Sanholt if (map->bsr != NULL) { 346145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 347145132Sanholt map->bsr); 348145132Sanholt } 349145132Sanholt 350145132Sanholt free(map, M_DRM); 351145132Sanholt} 352145132Sanholt 353145132Sanholt/* Remove a map private from list and deallocate resources if the mapping 354145132Sanholt * isn't in use. 355145132Sanholt */ 356145132Sanholt 357182080Srnolandint drm_rmmap_ioctl(struct drm_device *dev, void *data, 358182080Srnoland struct drm_file *file_priv) 359145132Sanholt{ 360145132Sanholt drm_local_map_t *map; 361182080Srnoland drm_map_t *request = data; 362145132Sanholt 363145132Sanholt DRM_LOCK(); 364145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 365182080Srnoland if (map->handle == request->handle && 366145132Sanholt map->flags & _DRM_REMOVABLE) 367145132Sanholt break; 368145132Sanholt } 369145132Sanholt 370145132Sanholt /* No match found. */ 371145132Sanholt if (map == NULL) { 372145132Sanholt DRM_UNLOCK(); 373182080Srnoland return EINVAL; 374145132Sanholt } 375145132Sanholt 376152909Sanholt drm_rmmap(dev, map); 377145132Sanholt 378145132Sanholt DRM_UNLOCK(); 379145132Sanholt 380145132Sanholt return 0; 381145132Sanholt} 382145132Sanholt 383145132Sanholt 384182080Srnolandstatic void drm_cleanup_buf_error(struct drm_device *dev, 385182080Srnoland drm_buf_entry_t *entry) 386145132Sanholt{ 387145132Sanholt int i; 388145132Sanholt 389145132Sanholt if (entry->seg_count) { 390145132Sanholt for (i = 0; i < entry->seg_count; i++) { 391152909Sanholt drm_pci_free(dev, entry->seglist[i]); 392145132Sanholt } 393145132Sanholt free(entry->seglist, M_DRM); 394145132Sanholt 395145132Sanholt entry->seg_count = 0; 396145132Sanholt } 397145132Sanholt 398145132Sanholt if (entry->buf_count) { 399145132Sanholt for (i = 0; i < entry->buf_count; i++) { 400145132Sanholt free(entry->buflist[i].dev_private, M_DRM); 401145132Sanholt } 402145132Sanholt free(entry->buflist, M_DRM); 403145132Sanholt 404145132Sanholt entry->buf_count = 0; 405145132Sanholt } 406145132Sanholt} 407145132Sanholt 408182080Srnolandstatic int drm_do_addbufs_agp(struct drm_device *dev, drm_buf_desc_t *request) 409145132Sanholt{ 410145132Sanholt drm_device_dma_t *dma = dev->dma; 411145132Sanholt drm_buf_entry_t *entry; 412152909Sanholt /*drm_agp_mem_t *agp_entry; 413152909Sanholt int valid*/ 414145132Sanholt drm_buf_t *buf; 415145132Sanholt unsigned long offset; 416145132Sanholt unsigned long agp_offset; 417145132Sanholt int count; 418145132Sanholt int order; 419145132Sanholt int size; 420145132Sanholt int alignment; 421145132Sanholt int page_order; 422145132Sanholt int total; 423145132Sanholt int byte_count; 424145132Sanholt int i; 425145132Sanholt drm_buf_t **temp_buflist; 426145132Sanholt 427145132Sanholt count = request->count; 428145132Sanholt order = drm_order(request->size); 429145132Sanholt size = 1 << order; 430145132Sanholt 431145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 432145132Sanholt ? round_page(size) : size; 433145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 434145132Sanholt total = PAGE_SIZE << page_order; 435145132Sanholt 436145132Sanholt byte_count = 0; 437145132Sanholt agp_offset = dev->agp->base + request->agp_start; 438145132Sanholt 439145132Sanholt DRM_DEBUG( "count: %d\n", count ); 440145132Sanholt DRM_DEBUG( "order: %d\n", order ); 441145132Sanholt DRM_DEBUG( "size: %d\n", size ); 442145132Sanholt DRM_DEBUG( "agp_offset: 0x%lx\n", agp_offset ); 443145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 444145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 445145132Sanholt DRM_DEBUG( "total: %d\n", total ); 446145132Sanholt 447152909Sanholt /* Make sure buffers are located in AGP memory that we own */ 448152909Sanholt /* Breaks MGA due to drm_alloc_agp not setting up entries for the 449152909Sanholt * memory. Safe to ignore for now because these ioctls are still 450152909Sanholt * root-only. 451152909Sanholt */ 452152909Sanholt /*valid = 0; 453152909Sanholt for (agp_entry = dev->agp->memory; agp_entry; 454152909Sanholt agp_entry = agp_entry->next) { 455152909Sanholt if ((agp_offset >= agp_entry->bound) && 456152909Sanholt (agp_offset + total * count <= 457152909Sanholt agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 458152909Sanholt valid = 1; 459152909Sanholt break; 460152909Sanholt } 461152909Sanholt } 462152909Sanholt if (!valid) { 463152909Sanholt DRM_DEBUG("zone invalid\n"); 464182080Srnoland return EINVAL; 465152909Sanholt }*/ 466152909Sanholt 467145132Sanholt entry = &dma->bufs[order]; 468145132Sanholt 469145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 470145132Sanholt M_NOWAIT | M_ZERO); 471145132Sanholt if ( !entry->buflist ) { 472182080Srnoland return ENOMEM; 473145132Sanholt } 474145132Sanholt 475145132Sanholt entry->buf_size = size; 476145132Sanholt entry->page_order = page_order; 477145132Sanholt 478145132Sanholt offset = 0; 479145132Sanholt 480145132Sanholt while ( entry->buf_count < count ) { 481145132Sanholt buf = &entry->buflist[entry->buf_count]; 482145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 483145132Sanholt buf->total = alignment; 484145132Sanholt buf->order = order; 485145132Sanholt buf->used = 0; 486145132Sanholt 487145132Sanholt buf->offset = (dma->byte_count + offset); 488145132Sanholt buf->bus_address = agp_offset + offset; 489145132Sanholt buf->address = (void *)(agp_offset + offset); 490145132Sanholt buf->next = NULL; 491145132Sanholt buf->pending = 0; 492182080Srnoland buf->file_priv = NULL; 493145132Sanholt 494152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 495145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 496145132Sanholt M_NOWAIT | M_ZERO); 497145132Sanholt if (buf->dev_private == NULL) { 498145132Sanholt /* Set count correctly so we free the proper amount. */ 499145132Sanholt entry->buf_count = count; 500145132Sanholt drm_cleanup_buf_error(dev, entry); 501182080Srnoland return ENOMEM; 502145132Sanholt } 503145132Sanholt 504145132Sanholt offset += alignment; 505145132Sanholt entry->buf_count++; 506145132Sanholt byte_count += PAGE_SIZE << page_order; 507145132Sanholt } 508145132Sanholt 509145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 510145132Sanholt 511145132Sanholt temp_buflist = realloc(dma->buflist, 512145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 513145132Sanholt M_NOWAIT); 514145132Sanholt if (temp_buflist == NULL) { 515145132Sanholt /* Free the entry because it isn't valid */ 516145132Sanholt drm_cleanup_buf_error(dev, entry); 517182080Srnoland return ENOMEM; 518145132Sanholt } 519145132Sanholt dma->buflist = temp_buflist; 520145132Sanholt 521145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 522145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 523145132Sanholt } 524145132Sanholt 525145132Sanholt dma->buf_count += entry->buf_count; 526145132Sanholt dma->byte_count += byte_count; 527145132Sanholt 528145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 529145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 530145132Sanholt 531145132Sanholt request->count = entry->buf_count; 532145132Sanholt request->size = size; 533145132Sanholt 534145132Sanholt dma->flags = _DRM_DMA_USE_AGP; 535145132Sanholt 536145132Sanholt return 0; 537145132Sanholt} 538145132Sanholt 539182080Srnolandstatic int drm_do_addbufs_pci(struct drm_device *dev, drm_buf_desc_t *request) 540145132Sanholt{ 541145132Sanholt drm_device_dma_t *dma = dev->dma; 542145132Sanholt int count; 543145132Sanholt int order; 544145132Sanholt int size; 545145132Sanholt int total; 546145132Sanholt int page_order; 547145132Sanholt drm_buf_entry_t *entry; 548145132Sanholt drm_buf_t *buf; 549145132Sanholt int alignment; 550145132Sanholt unsigned long offset; 551145132Sanholt int i; 552145132Sanholt int byte_count; 553145132Sanholt int page_count; 554145132Sanholt unsigned long *temp_pagelist; 555145132Sanholt drm_buf_t **temp_buflist; 556145132Sanholt 557145132Sanholt count = request->count; 558145132Sanholt order = drm_order(request->size); 559145132Sanholt size = 1 << order; 560145132Sanholt 561145132Sanholt DRM_DEBUG( "count=%d, size=%d (%d), order=%d\n", 562145132Sanholt request->count, request->size, size, order ); 563145132Sanholt 564145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 565145132Sanholt ? round_page(size) : size; 566145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 567145132Sanholt total = PAGE_SIZE << page_order; 568145132Sanholt 569145132Sanholt entry = &dma->bufs[order]; 570145132Sanholt 571145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 572145132Sanholt M_NOWAIT | M_ZERO); 573145132Sanholt entry->seglist = malloc(count * sizeof(*entry->seglist), M_DRM, 574145132Sanholt M_NOWAIT | M_ZERO); 575145132Sanholt 576145132Sanholt /* Keep the original pagelist until we know all the allocations 577145132Sanholt * have succeeded 578145132Sanholt */ 579145132Sanholt temp_pagelist = malloc((dma->page_count + (count << page_order)) * 580145132Sanholt sizeof(*dma->pagelist), M_DRM, M_NOWAIT); 581145132Sanholt 582145132Sanholt if (entry->buflist == NULL || entry->seglist == NULL || 583152909Sanholt temp_pagelist == NULL) { 584145132Sanholt free(entry->buflist, M_DRM); 585145132Sanholt free(entry->seglist, M_DRM); 586182080Srnoland return ENOMEM; 587145132Sanholt } 588145132Sanholt 589145132Sanholt memcpy(temp_pagelist, dma->pagelist, dma->page_count * 590145132Sanholt sizeof(*dma->pagelist)); 591145132Sanholt 592145132Sanholt DRM_DEBUG( "pagelist: %d entries\n", 593145132Sanholt dma->page_count + (count << page_order) ); 594145132Sanholt 595145132Sanholt entry->buf_size = size; 596145132Sanholt entry->page_order = page_order; 597145132Sanholt byte_count = 0; 598145132Sanholt page_count = 0; 599145132Sanholt 600145132Sanholt while ( entry->buf_count < count ) { 601152909Sanholt drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 602152909Sanholt 0xfffffffful); 603152909Sanholt if (dmah == NULL) { 604145132Sanholt /* Set count correctly so we free the proper amount. */ 605145132Sanholt entry->buf_count = count; 606145132Sanholt entry->seg_count = count; 607145132Sanholt drm_cleanup_buf_error(dev, entry); 608145132Sanholt free(temp_pagelist, M_DRM); 609182080Srnoland return ENOMEM; 610145132Sanholt } 611152909Sanholt 612152909Sanholt entry->seglist[entry->seg_count++] = dmah; 613145132Sanholt for ( i = 0 ; i < (1 << page_order) ; i++ ) { 614152909Sanholt DRM_DEBUG( "page %d @ %p\n", 615145132Sanholt dma->page_count + page_count, 616152909Sanholt (char *)dmah->vaddr + PAGE_SIZE * i ); 617145132Sanholt temp_pagelist[dma->page_count + page_count++] = 618152909Sanholt (long)dmah->vaddr + PAGE_SIZE * i; 619145132Sanholt } 620145132Sanholt for ( offset = 0 ; 621145132Sanholt offset + size <= total && entry->buf_count < count ; 622145132Sanholt offset += alignment, ++entry->buf_count ) { 623145132Sanholt buf = &entry->buflist[entry->buf_count]; 624145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 625145132Sanholt buf->total = alignment; 626145132Sanholt buf->order = order; 627145132Sanholt buf->used = 0; 628145132Sanholt buf->offset = (dma->byte_count + byte_count + offset); 629152909Sanholt buf->address = ((char *)dmah->vaddr + offset); 630152909Sanholt buf->bus_address = dmah->busaddr + offset; 631145132Sanholt buf->next = NULL; 632145132Sanholt buf->pending = 0; 633182080Srnoland buf->file_priv = NULL; 634145132Sanholt 635152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 636145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 637145132Sanholt M_NOWAIT | M_ZERO); 638145132Sanholt if (buf->dev_private == NULL) { 639145132Sanholt /* Set count correctly so we free the proper amount. */ 640145132Sanholt entry->buf_count = count; 641145132Sanholt entry->seg_count = count; 642145132Sanholt drm_cleanup_buf_error(dev, entry); 643145132Sanholt free(temp_pagelist, M_DRM); 644182080Srnoland return ENOMEM; 645145132Sanholt } 646145132Sanholt 647145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 648145132Sanholt entry->buf_count, buf->address ); 649145132Sanholt } 650145132Sanholt byte_count += PAGE_SIZE << page_order; 651145132Sanholt } 652145132Sanholt 653145132Sanholt temp_buflist = realloc(dma->buflist, 654145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 655145132Sanholt M_NOWAIT); 656145132Sanholt if (temp_buflist == NULL) { 657145132Sanholt /* Free the entry because it isn't valid */ 658145132Sanholt drm_cleanup_buf_error(dev, entry); 659145132Sanholt free(temp_pagelist, M_DRM); 660182080Srnoland return ENOMEM; 661145132Sanholt } 662145132Sanholt dma->buflist = temp_buflist; 663145132Sanholt 664145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 665145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 666145132Sanholt } 667145132Sanholt 668145132Sanholt /* No allocations failed, so now we can replace the orginal pagelist 669145132Sanholt * with the new one. 670145132Sanholt */ 671145132Sanholt free(dma->pagelist, M_DRM); 672145132Sanholt dma->pagelist = temp_pagelist; 673145132Sanholt 674145132Sanholt dma->buf_count += entry->buf_count; 675145132Sanholt dma->seg_count += entry->seg_count; 676145132Sanholt dma->page_count += entry->seg_count << page_order; 677145132Sanholt dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 678145132Sanholt 679145132Sanholt request->count = entry->buf_count; 680145132Sanholt request->size = size; 681145132Sanholt 682145132Sanholt return 0; 683145132Sanholt 684145132Sanholt} 685145132Sanholt 686182080Srnolandstatic int drm_do_addbufs_sg(struct drm_device *dev, drm_buf_desc_t *request) 687145132Sanholt{ 688145132Sanholt drm_device_dma_t *dma = dev->dma; 689145132Sanholt drm_buf_entry_t *entry; 690145132Sanholt drm_buf_t *buf; 691145132Sanholt unsigned long offset; 692145132Sanholt unsigned long agp_offset; 693145132Sanholt int count; 694145132Sanholt int order; 695145132Sanholt int size; 696145132Sanholt int alignment; 697145132Sanholt int page_order; 698145132Sanholt int total; 699145132Sanholt int byte_count; 700145132Sanholt int i; 701145132Sanholt drm_buf_t **temp_buflist; 702145132Sanholt 703145132Sanholt count = request->count; 704145132Sanholt order = drm_order(request->size); 705145132Sanholt size = 1 << order; 706145132Sanholt 707145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 708145132Sanholt ? round_page(size) : size; 709145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 710145132Sanholt total = PAGE_SIZE << page_order; 711145132Sanholt 712145132Sanholt byte_count = 0; 713145132Sanholt agp_offset = request->agp_start; 714145132Sanholt 715145132Sanholt DRM_DEBUG( "count: %d\n", count ); 716145132Sanholt DRM_DEBUG( "order: %d\n", order ); 717145132Sanholt DRM_DEBUG( "size: %d\n", size ); 718145132Sanholt DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); 719145132Sanholt DRM_DEBUG( "alignment: %d\n", alignment ); 720145132Sanholt DRM_DEBUG( "page_order: %d\n", page_order ); 721145132Sanholt DRM_DEBUG( "total: %d\n", total ); 722145132Sanholt 723145132Sanholt entry = &dma->bufs[order]; 724145132Sanholt 725145132Sanholt entry->buflist = malloc(count * sizeof(*entry->buflist), M_DRM, 726145132Sanholt M_NOWAIT | M_ZERO); 727145132Sanholt if (entry->buflist == NULL) 728182080Srnoland return ENOMEM; 729145132Sanholt 730145132Sanholt entry->buf_size = size; 731145132Sanholt entry->page_order = page_order; 732145132Sanholt 733145132Sanholt offset = 0; 734145132Sanholt 735145132Sanholt while ( entry->buf_count < count ) { 736145132Sanholt buf = &entry->buflist[entry->buf_count]; 737145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 738145132Sanholt buf->total = alignment; 739145132Sanholt buf->order = order; 740145132Sanholt buf->used = 0; 741145132Sanholt 742145132Sanholt buf->offset = (dma->byte_count + offset); 743145132Sanholt buf->bus_address = agp_offset + offset; 744145132Sanholt buf->address = (void *)(agp_offset + offset + dev->sg->handle); 745145132Sanholt buf->next = NULL; 746145132Sanholt buf->pending = 0; 747182080Srnoland buf->file_priv = NULL; 748145132Sanholt 749152909Sanholt buf->dev_priv_size = dev->driver.buf_priv_size; 750145132Sanholt buf->dev_private = malloc(buf->dev_priv_size, M_DRM, 751145132Sanholt M_NOWAIT | M_ZERO); 752145132Sanholt if (buf->dev_private == NULL) { 753145132Sanholt /* Set count correctly so we free the proper amount. */ 754145132Sanholt entry->buf_count = count; 755145132Sanholt drm_cleanup_buf_error(dev, entry); 756182080Srnoland return ENOMEM; 757145132Sanholt } 758145132Sanholt 759145132Sanholt DRM_DEBUG( "buffer %d @ %p\n", 760145132Sanholt entry->buf_count, buf->address ); 761145132Sanholt 762145132Sanholt offset += alignment; 763145132Sanholt entry->buf_count++; 764145132Sanholt byte_count += PAGE_SIZE << page_order; 765145132Sanholt } 766145132Sanholt 767145132Sanholt DRM_DEBUG( "byte_count: %d\n", byte_count ); 768145132Sanholt 769145132Sanholt temp_buflist = realloc(dma->buflist, 770145132Sanholt (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), M_DRM, 771145132Sanholt M_NOWAIT); 772145132Sanholt if (temp_buflist == NULL) { 773145132Sanholt /* Free the entry because it isn't valid */ 774145132Sanholt drm_cleanup_buf_error(dev, entry); 775182080Srnoland return ENOMEM; 776145132Sanholt } 777145132Sanholt dma->buflist = temp_buflist; 778145132Sanholt 779145132Sanholt for ( i = 0 ; i < entry->buf_count ; i++ ) { 780145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 781145132Sanholt } 782145132Sanholt 783145132Sanholt dma->buf_count += entry->buf_count; 784145132Sanholt dma->byte_count += byte_count; 785145132Sanholt 786145132Sanholt DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); 787145132Sanholt DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); 788145132Sanholt 789145132Sanholt request->count = entry->buf_count; 790145132Sanholt request->size = size; 791145132Sanholt 792145132Sanholt dma->flags = _DRM_DMA_USE_SG; 793145132Sanholt 794145132Sanholt return 0; 795145132Sanholt} 796145132Sanholt 797182080Srnolandint drm_addbufs_agp(struct drm_device *dev, drm_buf_desc_t *request) 798145132Sanholt{ 799152909Sanholt int order, ret; 800145132Sanholt 801152909Sanholt if (request->count < 0 || request->count > 4096) 802182080Srnoland return EINVAL; 803152909Sanholt 804152909Sanholt order = drm_order(request->size); 805152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 806182080Srnoland return EINVAL; 807145132Sanholt 808182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 809182080Srnoland 810152909Sanholt /* No more allocations after first buffer-using ioctl. */ 811152909Sanholt if (dev->buf_use != 0) { 812152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 813182080Srnoland return EBUSY; 814152909Sanholt } 815152909Sanholt /* No more than one allocation per order */ 816152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 817152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 818182080Srnoland return ENOMEM; 819152909Sanholt } 820152909Sanholt 821152909Sanholt ret = drm_do_addbufs_agp(dev, request); 822152909Sanholt 823152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 824152909Sanholt 825152909Sanholt return ret; 826152909Sanholt} 827152909Sanholt 828182080Srnolandint drm_addbufs_sg(struct drm_device *dev, drm_buf_desc_t *request) 829152909Sanholt{ 830152909Sanholt int order, ret; 831152909Sanholt 832152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 833182080Srnoland return EACCES; 834152909Sanholt 835152909Sanholt if (request->count < 0 || request->count > 4096) 836182080Srnoland return EINVAL; 837182080Srnoland 838152909Sanholt order = drm_order(request->size); 839145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 840182080Srnoland return EINVAL; 841145132Sanholt 842182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 843182080Srnoland 844152909Sanholt /* No more allocations after first buffer-using ioctl. */ 845152909Sanholt if (dev->buf_use != 0) { 846152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 847182080Srnoland return EBUSY; 848152909Sanholt } 849152909Sanholt /* No more than one allocation per order */ 850152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 851152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 852182080Srnoland return ENOMEM; 853152909Sanholt } 854152909Sanholt 855152909Sanholt ret = drm_do_addbufs_sg(dev, request); 856152909Sanholt 857152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 858152909Sanholt 859152909Sanholt return ret; 860152909Sanholt} 861152909Sanholt 862182080Srnolandint drm_addbufs_pci(struct drm_device *dev, drm_buf_desc_t *request) 863152909Sanholt{ 864152909Sanholt int order, ret; 865152909Sanholt 866152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 867182080Srnoland return EACCES; 868152909Sanholt 869152909Sanholt if (request->count < 0 || request->count > 4096) 870182080Srnoland return EINVAL; 871182080Srnoland 872152909Sanholt order = drm_order(request->size); 873152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 874182080Srnoland return EINVAL; 875152909Sanholt 876182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 877182080Srnoland 878145132Sanholt /* No more allocations after first buffer-using ioctl. */ 879145132Sanholt if (dev->buf_use != 0) { 880145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 881182080Srnoland return EBUSY; 882145132Sanholt } 883145132Sanholt /* No more than one allocation per order */ 884145132Sanholt if (dev->dma->bufs[order].buf_count != 0) { 885145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 886182080Srnoland return ENOMEM; 887145132Sanholt } 888145132Sanholt 889152909Sanholt ret = drm_do_addbufs_pci(dev, request); 890152909Sanholt 891152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 892152909Sanholt 893152909Sanholt return ret; 894152909Sanholt} 895152909Sanholt 896182080Srnolandint drm_addbufs_ioctl(struct drm_device *dev, void *data, 897182080Srnoland struct drm_file *file_priv) 898152909Sanholt{ 899182080Srnoland drm_buf_desc_t *request = data; 900152909Sanholt int err; 901152909Sanholt 902182080Srnoland if (request->flags & _DRM_AGP_BUFFER) 903182080Srnoland err = drm_addbufs_agp(dev, request); 904182080Srnoland else if (request->flags & _DRM_SG_BUFFER) 905182080Srnoland err = drm_addbufs_sg(dev, request); 906145132Sanholt else 907182080Srnoland err = drm_addbufs_pci(dev, request); 908145132Sanholt 909145132Sanholt return err; 910145132Sanholt} 911145132Sanholt 912182080Srnolandint drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 913145132Sanholt{ 914145132Sanholt drm_device_dma_t *dma = dev->dma; 915182080Srnoland drm_buf_info_t *request = data; 916145132Sanholt int i; 917145132Sanholt int count; 918145132Sanholt int retcode = 0; 919145132Sanholt 920145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 921145132Sanholt ++dev->buf_use; /* Can't allocate more after this call */ 922145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 923145132Sanholt 924145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 925145132Sanholt if ( dma->bufs[i].buf_count ) ++count; 926145132Sanholt } 927145132Sanholt 928145132Sanholt DRM_DEBUG( "count = %d\n", count ); 929145132Sanholt 930182080Srnoland if ( request->count >= count ) { 931145132Sanholt for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { 932145132Sanholt if ( dma->bufs[i].buf_count ) { 933145132Sanholt drm_buf_desc_t from; 934145132Sanholt 935145132Sanholt from.count = dma->bufs[i].buf_count; 936145132Sanholt from.size = dma->bufs[i].buf_size; 937145132Sanholt from.low_mark = dma->bufs[i].freelist.low_mark; 938145132Sanholt from.high_mark = dma->bufs[i].freelist.high_mark; 939145132Sanholt 940182080Srnoland if (DRM_COPY_TO_USER(&request->list[count], &from, 941145132Sanholt sizeof(drm_buf_desc_t)) != 0) { 942182080Srnoland retcode = EFAULT; 943145132Sanholt break; 944145132Sanholt } 945145132Sanholt 946145132Sanholt DRM_DEBUG( "%d %d %d %d %d\n", 947145132Sanholt i, 948145132Sanholt dma->bufs[i].buf_count, 949145132Sanholt dma->bufs[i].buf_size, 950145132Sanholt dma->bufs[i].freelist.low_mark, 951145132Sanholt dma->bufs[i].freelist.high_mark ); 952145132Sanholt ++count; 953145132Sanholt } 954145132Sanholt } 955145132Sanholt } 956182080Srnoland request->count = count; 957145132Sanholt 958145132Sanholt return retcode; 959145132Sanholt} 960145132Sanholt 961182080Srnolandint drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 962145132Sanholt{ 963145132Sanholt drm_device_dma_t *dma = dev->dma; 964182080Srnoland drm_buf_desc_t *request = data; 965145132Sanholt int order; 966145132Sanholt 967145132Sanholt DRM_DEBUG( "%d, %d, %d\n", 968182080Srnoland request->size, request->low_mark, request->high_mark ); 969145132Sanholt 970145132Sanholt 971182080Srnoland order = drm_order(request->size); 972145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 973182080Srnoland request->low_mark < 0 || request->high_mark < 0) { 974182080Srnoland return EINVAL; 975145132Sanholt } 976145132Sanholt 977145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 978182080Srnoland if (request->low_mark > dma->bufs[order].buf_count || 979182080Srnoland request->high_mark > dma->bufs[order].buf_count) { 980182080Srnoland DRM_SPINUNLOCK(&dev->dma_lock); 981182080Srnoland return EINVAL; 982145132Sanholt } 983145132Sanholt 984182080Srnoland dma->bufs[order].freelist.low_mark = request->low_mark; 985182080Srnoland dma->bufs[order].freelist.high_mark = request->high_mark; 986145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 987145132Sanholt 988145132Sanholt return 0; 989145132Sanholt} 990145132Sanholt 991182080Srnolandint drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 992145132Sanholt{ 993145132Sanholt drm_device_dma_t *dma = dev->dma; 994182080Srnoland drm_buf_free_t *request = data; 995145132Sanholt int i; 996145132Sanholt int idx; 997145132Sanholt drm_buf_t *buf; 998145132Sanholt int retcode = 0; 999145132Sanholt 1000182080Srnoland DRM_DEBUG( "%d\n", request->count ); 1001145132Sanholt 1002145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 1003182080Srnoland for ( i = 0 ; i < request->count ; i++ ) { 1004182080Srnoland if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { 1005182080Srnoland retcode = EFAULT; 1006145132Sanholt break; 1007145132Sanholt } 1008145132Sanholt if ( idx < 0 || idx >= dma->buf_count ) { 1009145132Sanholt DRM_ERROR( "Index %d (of %d max)\n", 1010145132Sanholt idx, dma->buf_count - 1 ); 1011182080Srnoland retcode = EINVAL; 1012145132Sanholt break; 1013145132Sanholt } 1014145132Sanholt buf = dma->buflist[idx]; 1015182080Srnoland if ( buf->file_priv != file_priv ) { 1016145132Sanholt DRM_ERROR("Process %d freeing buffer not owned\n", 1017145132Sanholt DRM_CURRENTPID); 1018182080Srnoland retcode = EINVAL; 1019145132Sanholt break; 1020145132Sanholt } 1021145132Sanholt drm_free_buffer(dev, buf); 1022145132Sanholt } 1023145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1024145132Sanholt 1025145132Sanholt return retcode; 1026145132Sanholt} 1027145132Sanholt 1028182080Srnolandint drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 1029145132Sanholt{ 1030145132Sanholt drm_device_dma_t *dma = dev->dma; 1031145132Sanholt int retcode = 0; 1032145132Sanholt const int zero = 0; 1033145132Sanholt vm_offset_t address; 1034145132Sanholt struct vmspace *vms; 1035145132Sanholt#ifdef __FreeBSD__ 1036145132Sanholt vm_ooffset_t foff; 1037145132Sanholt vm_size_t size; 1038145132Sanholt vm_offset_t vaddr; 1039145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 1040145132Sanholt struct vnode *vn; 1041152909Sanholt voff_t foff; 1042152909Sanholt vsize_t size; 1043145132Sanholt vaddr_t vaddr; 1044145132Sanholt#endif /* __NetBSD__ || __OpenBSD__ */ 1045145132Sanholt 1046182080Srnoland drm_buf_map_t *request = data; 1047145132Sanholt int i; 1048145132Sanholt 1049145132Sanholt#if defined(__NetBSD__) || defined(__OpenBSD__) 1050145132Sanholt if (!vfinddev(kdev, VCHR, &vn)) 1051145132Sanholt return 0; /* FIXME: Shouldn't this be EINVAL or something? */ 1052145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 1053145132Sanholt 1054145132Sanholt#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1055182080Srnoland vms = DRM_CURPROC->td_proc->p_vmspace; 1056145132Sanholt#else 1057182080Srnoland vms = DRM_CURPROC->p_vmspace; 1058145132Sanholt#endif 1059145132Sanholt 1060145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 1061145132Sanholt dev->buf_use++; /* Can't allocate more after this call */ 1062145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1063145132Sanholt 1064182080Srnoland if (request->count < dma->buf_count) 1065145132Sanholt goto done; 1066145132Sanholt 1067152909Sanholt if ((dev->driver.use_agp && (dma->flags & _DRM_DMA_USE_AGP)) || 1068152909Sanholt (dev->driver.use_sg && (dma->flags & _DRM_DMA_USE_SG))) { 1069145132Sanholt drm_local_map_t *map = dev->agp_buffer_map; 1070145132Sanholt 1071145132Sanholt if (map == NULL) { 1072145132Sanholt retcode = EINVAL; 1073145132Sanholt goto done; 1074145132Sanholt } 1075145132Sanholt size = round_page(map->size); 1076145132Sanholt foff = map->offset; 1077145132Sanholt } else { 1078145132Sanholt size = round_page(dma->byte_count), 1079145132Sanholt foff = 0; 1080145132Sanholt } 1081145132Sanholt 1082145132Sanholt#ifdef __FreeBSD__ 1083145132Sanholt vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1084145132Sanholt#if __FreeBSD_version >= 600023 1085145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1086182080Srnoland VM_PROT_ALL, MAP_SHARED, OBJT_DEVICE, dev->devnode, foff); 1087145132Sanholt#else 1088145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1089182080Srnoland VM_PROT_ALL, MAP_SHARED, SLIST_FIRST(&dev->devnode->si_hlist), 1090182080Srnoland foff); 1091145132Sanholt#endif 1092145132Sanholt#elif defined(__NetBSD__) || defined(__OpenBSD__) 1093145132Sanholt vaddr = round_page((vaddr_t)vms->vm_daddr + MAXDSIZ); 1094145132Sanholt retcode = uvm_mmap(&vms->vm_map, &vaddr, size, 1095145132Sanholt UVM_PROT_READ | UVM_PROT_WRITE, UVM_PROT_ALL, MAP_SHARED, 1096145132Sanholt &vn->v_uobj, foff, p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur); 1097145132Sanholt#endif /* __NetBSD__ || __OpenBSD */ 1098145132Sanholt if (retcode) 1099145132Sanholt goto done; 1100145132Sanholt 1101182080Srnoland request->virtual = (void *)vaddr; 1102145132Sanholt 1103145132Sanholt for ( i = 0 ; i < dma->buf_count ; i++ ) { 1104182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].idx, 1105182080Srnoland &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 1106145132Sanholt retcode = EFAULT; 1107145132Sanholt goto done; 1108145132Sanholt } 1109182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].total, 1110182080Srnoland &dma->buflist[i]->total, sizeof(request->list[0].total))) { 1111145132Sanholt retcode = EFAULT; 1112145132Sanholt goto done; 1113145132Sanholt } 1114182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].used, &zero, 1115145132Sanholt sizeof(zero))) { 1116145132Sanholt retcode = EFAULT; 1117145132Sanholt goto done; 1118145132Sanholt } 1119145132Sanholt address = vaddr + dma->buflist[i]->offset; /* *** */ 1120182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].address, &address, 1121145132Sanholt sizeof(address))) { 1122145132Sanholt retcode = EFAULT; 1123145132Sanholt goto done; 1124145132Sanholt } 1125145132Sanholt } 1126145132Sanholt 1127145132Sanholt done: 1128182080Srnoland request->count = dma->buf_count; 1129145132Sanholt 1130182080Srnoland DRM_DEBUG( "%d buffers, retcode = %d\n", request->count, retcode ); 1131145132Sanholt 1132182080Srnoland return retcode; 1133145132Sanholt} 1134