drm_bufs.c revision 331987
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: releng/10.3/sys/dev/drm/drm_bufs.c 331987 2018-04-04 05:43:03Z gordon $"); 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 42152909Sanholt/* Allocation of PCI memory resources (framebuffer, registers, etc.) for 43152909Sanholt * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 44152909Sanholt * address for accessing them. Cleaned up at unload. 45152909Sanholt */ 46182080Srnolandstatic int drm_alloc_resource(struct drm_device *dev, int resource) 47145132Sanholt{ 48196464Srnoland struct resource *res; 49196464Srnoland int rid; 50196464Srnoland 51196464Srnoland DRM_SPINLOCK_ASSERT(&dev->dev_lock); 52196464Srnoland 53152909Sanholt if (resource >= DRM_MAX_PCI_RESOURCE) { 54152909Sanholt DRM_ERROR("Resource %d too large\n", resource); 55152909Sanholt return 1; 56152909Sanholt } 57145132Sanholt 58152909Sanholt if (dev->pcir[resource] != NULL) { 59145132Sanholt return 0; 60145132Sanholt } 61145132Sanholt 62196464Srnoland DRM_UNLOCK(); 63196464Srnoland rid = PCIR_BAR(resource); 64196464Srnoland res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid, 65196464Srnoland RF_SHAREABLE); 66152909Sanholt DRM_LOCK(); 67196464Srnoland if (res == NULL) { 68152909Sanholt DRM_ERROR("Couldn't find resource 0x%x\n", resource); 69152909Sanholt return 1; 70152909Sanholt } 71145132Sanholt 72196464Srnoland if (dev->pcir[resource] == NULL) { 73196464Srnoland dev->pcirid[resource] = rid; 74196464Srnoland dev->pcir[resource] = res; 75196464Srnoland } 76196464Srnoland 77152909Sanholt return 0; 78145132Sanholt} 79145132Sanholt 80182080Srnolandunsigned long drm_get_resource_start(struct drm_device *dev, 81182080Srnoland unsigned int resource) 82145132Sanholt{ 83152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 84152909Sanholt return 0; 85145132Sanholt 86152909Sanholt return rman_get_start(dev->pcir[resource]); 87145132Sanholt} 88145132Sanholt 89182080Srnolandunsigned long drm_get_resource_len(struct drm_device *dev, 90182080Srnoland unsigned int resource) 91145132Sanholt{ 92152909Sanholt if (drm_alloc_resource(dev, resource) != 0) 93152909Sanholt return 0; 94145132Sanholt 95152909Sanholt return rman_get_size(dev->pcir[resource]); 96145132Sanholt} 97145132Sanholt 98182080Srnolandint drm_addmap(struct drm_device * dev, unsigned long offset, 99182080Srnoland unsigned long size, 100183573Srnoland enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr) 101145132Sanholt{ 102145132Sanholt drm_local_map_t *map; 103152909Sanholt int align; 104152909Sanholt /*drm_agp_mem_t *entry; 105152909Sanholt int valid;*/ 106145132Sanholt 107145132Sanholt /* Only allow shared memory to be removable since we only keep enough 108145132Sanholt * book keeping information about shared memory to allow for removal 109145132Sanholt * when processes fork. 110145132Sanholt */ 111152909Sanholt if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 112152909Sanholt DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 113145132Sanholt return EINVAL; 114152909Sanholt } 115152909Sanholt if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 116152909Sanholt DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 117152909Sanholt offset, size); 118145132Sanholt return EINVAL; 119152909Sanholt } 120152909Sanholt if (offset + size < offset) { 121152909Sanholt DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 122152909Sanholt offset, size); 123145132Sanholt return EINVAL; 124152909Sanholt } 125145132Sanholt 126152909Sanholt DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 127152909Sanholt size, type); 128145132Sanholt 129145132Sanholt /* Check if this is just another version of a kernel-allocated map, and 130145132Sanholt * just hand that back if so. 131145132Sanholt */ 132152909Sanholt if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 133152909Sanholt type == _DRM_SHM) { 134145132Sanholt TAILQ_FOREACH(map, &dev->maplist, link) { 135152909Sanholt if (map->type == type && (map->offset == offset || 136152909Sanholt (map->type == _DRM_SHM && 137152909Sanholt map->flags == _DRM_CONTAINS_LOCK))) { 138152909Sanholt map->size = size; 139152909Sanholt DRM_DEBUG("Found kernel map %d\n", type); 140145132Sanholt goto done; 141145132Sanholt } 142145132Sanholt } 143145132Sanholt } 144152909Sanholt DRM_UNLOCK(); 145145132Sanholt 146145132Sanholt /* Allocate a new map structure, fill it in, and do any type-specific 147145132Sanholt * initialization necessary. 148145132Sanholt */ 149183833Srnoland map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); 150183573Srnoland if (!map) { 151182080Srnoland DRM_LOCK(); 152182080Srnoland return ENOMEM; 153182080Srnoland } 154145132Sanholt 155152909Sanholt map->offset = offset; 156152909Sanholt map->size = size; 157152909Sanholt map->type = type; 158152909Sanholt map->flags = flags; 159207066Srnoland map->handle = (void *)((unsigned long)alloc_unr(dev->map_unrhdr) << 160207066Srnoland DRM_MAP_HANDLE_SHIFT); 161145132Sanholt 162183573Srnoland switch (map->type) { 163145132Sanholt case _DRM_REGISTERS: 164207066Srnoland map->virtual = 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: 173207066Srnoland map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT); 174183573Srnoland DRM_DEBUG("%lu %d %p\n", 175207066Srnoland map->size, drm_order(map->size), map->virtual); 176207066Srnoland if (!map->virtual) { 177183833Srnoland free(map, DRM_MEM_MAPS); 178182080Srnoland DRM_LOCK(); 179182080Srnoland return ENOMEM; 180145132Sanholt } 181207066Srnoland map->offset = (unsigned long)map->virtual; 182183573Srnoland if (map->flags & _DRM_CONTAINS_LOCK) { 183145132Sanholt /* Prevent a 2nd X Server from creating a 2nd lock */ 184145132Sanholt DRM_LOCK(); 185145132Sanholt if (dev->lock.hw_lock != NULL) { 186145132Sanholt DRM_UNLOCK(); 187207066Srnoland free(map->virtual, DRM_MEM_MAPS); 188183833Srnoland free(map, DRM_MEM_MAPS); 189182080Srnoland return EBUSY; 190145132Sanholt } 191207066Srnoland dev->lock.hw_lock = map->virtual; /* Pointer to lock */ 192145132Sanholt DRM_UNLOCK(); 193145132Sanholt } 194145132Sanholt break; 195145132Sanholt case _DRM_AGP: 196152909Sanholt /*valid = 0;*/ 197182080Srnoland /* In some cases (i810 driver), user space may have already 198182080Srnoland * added the AGP base itself, because dev->agp->base previously 199182080Srnoland * only got set during AGP enable. So, only add the base 200182080Srnoland * address if the map's offset isn't already within the 201182080Srnoland * aperture. 202182080Srnoland */ 203182080Srnoland if (map->offset < dev->agp->base || 204182080Srnoland map->offset > dev->agp->base + 205182080Srnoland dev->agp->info.ai_aperture_size - 1) { 206182080Srnoland map->offset += dev->agp->base; 207182080Srnoland } 208145132Sanholt map->mtrr = dev->agp->mtrr; /* for getmap */ 209152909Sanholt /*for (entry = dev->agp->memory; entry; entry = entry->next) { 210152909Sanholt if ((map->offset >= entry->bound) && 211152909Sanholt (map->offset + map->size <= 212152909Sanholt entry->bound + entry->pages * PAGE_SIZE)) { 213152909Sanholt valid = 1; 214152909Sanholt break; 215152909Sanholt } 216152909Sanholt } 217152909Sanholt if (!valid) { 218183833Srnoland free(map, DRM_MEM_MAPS); 219182080Srnoland DRM_LOCK(); 220182080Srnoland return EACCES; 221152909Sanholt }*/ 222145132Sanholt break; 223145132Sanholt case _DRM_SCATTER_GATHER: 224145132Sanholt if (!dev->sg) { 225183833Srnoland free(map, DRM_MEM_MAPS); 226182080Srnoland DRM_LOCK(); 227182080Srnoland return EINVAL; 228145132Sanholt } 229207067Srnoland map->virtual = (void *)(dev->sg->vaddr + offset); 230207067Srnoland map->offset = dev->sg->vaddr + offset; 231145132Sanholt break; 232145132Sanholt case _DRM_CONSISTENT: 233152909Sanholt /* Unfortunately, we don't get any alignment specification from 234152909Sanholt * the caller, so we have to guess. drm_pci_alloc requires 235152909Sanholt * a power-of-two alignment, so try to align the bus address of 236152909Sanholt * the map to it size if possible, otherwise just assume 237152909Sanholt * PAGE_SIZE alignment. 238152909Sanholt */ 239152909Sanholt align = map->size; 240152909Sanholt if ((align & (align - 1)) != 0) 241152909Sanholt align = PAGE_SIZE; 242152909Sanholt map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 243152909Sanholt if (map->dmah == NULL) { 244183833Srnoland free(map, DRM_MEM_MAPS); 245182080Srnoland DRM_LOCK(); 246182080Srnoland return ENOMEM; 247145132Sanholt } 248207066Srnoland map->virtual = map->dmah->vaddr; 249152909Sanholt map->offset = map->dmah->busaddr; 250145132Sanholt break; 251145132Sanholt default: 252152909Sanholt DRM_ERROR("Bad map type %d\n", map->type); 253183833Srnoland free(map, DRM_MEM_MAPS); 254182080Srnoland DRM_LOCK(); 255182080Srnoland return EINVAL; 256145132Sanholt } 257145132Sanholt 258145132Sanholt DRM_LOCK(); 259145132Sanholt TAILQ_INSERT_TAIL(&dev->maplist, map, link); 260145132Sanholt 261145132Sanholtdone: 262145132Sanholt /* Jumped to, with lock held, when a kernel map is found. */ 263152909Sanholt 264152909Sanholt DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 265152909Sanholt map->size); 266152909Sanholt 267152909Sanholt *map_ptr = map; 268152909Sanholt 269152909Sanholt return 0; 270152909Sanholt} 271152909Sanholt 272182080Srnolandint drm_addmap_ioctl(struct drm_device *dev, void *data, 273182080Srnoland struct drm_file *file_priv) 274152909Sanholt{ 275183573Srnoland struct drm_map *request = data; 276152909Sanholt drm_local_map_t *map; 277152909Sanholt int err; 278152909Sanholt 279152909Sanholt if (!(dev->flags & (FREAD|FWRITE))) 280182080Srnoland return EACCES; /* Require read/write */ 281152909Sanholt 282182080Srnoland if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) 283182080Srnoland return EACCES; 284152909Sanholt 285152909Sanholt DRM_LOCK(); 286182080Srnoland err = drm_addmap(dev, request->offset, request->size, request->type, 287182080Srnoland request->flags, &map); 288152909Sanholt DRM_UNLOCK(); 289152909Sanholt if (err != 0) 290152909Sanholt return err; 291152909Sanholt 292182080Srnoland request->offset = map->offset; 293182080Srnoland request->size = map->size; 294182080Srnoland request->type = map->type; 295182080Srnoland request->flags = map->flags; 296182080Srnoland request->mtrr = map->mtrr; 297207066Srnoland request->handle = (void *)map->handle; 298145132Sanholt 299145132Sanholt return 0; 300145132Sanholt} 301145132Sanholt 302182080Srnolandvoid drm_rmmap(struct drm_device *dev, drm_local_map_t *map) 303145132Sanholt{ 304145132Sanholt DRM_SPINLOCK_ASSERT(&dev->dev_lock); 305145132Sanholt 306194537Srnoland if (map == NULL) 307194537Srnoland return; 308194537Srnoland 309145132Sanholt TAILQ_REMOVE(&dev->maplist, map, link); 310145132Sanholt 311145132Sanholt switch (map->type) { 312145132Sanholt case _DRM_REGISTERS: 313145132Sanholt if (map->bsr == NULL) 314145132Sanholt drm_ioremapfree(map); 315145132Sanholt /* FALLTHROUGH */ 316145132Sanholt case _DRM_FRAME_BUFFER: 317145132Sanholt if (map->mtrr) { 318145132Sanholt int __unused retcode; 319145132Sanholt 320152909Sanholt retcode = drm_mtrr_del(0, map->offset, map->size, 321145132Sanholt DRM_MTRR_WC); 322145132Sanholt DRM_DEBUG("mtrr_del = %d\n", retcode); 323145132Sanholt } 324145132Sanholt break; 325145132Sanholt case _DRM_SHM: 326207066Srnoland free(map->virtual, DRM_MEM_MAPS); 327145132Sanholt break; 328145132Sanholt case _DRM_AGP: 329145132Sanholt case _DRM_SCATTER_GATHER: 330145132Sanholt break; 331145132Sanholt case _DRM_CONSISTENT: 332152909Sanholt drm_pci_free(dev, map->dmah); 333145132Sanholt break; 334182080Srnoland default: 335182080Srnoland DRM_ERROR("Bad map type %d\n", map->type); 336182080Srnoland break; 337145132Sanholt } 338145132Sanholt 339145132Sanholt if (map->bsr != NULL) { 340145132Sanholt bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 341145132Sanholt map->bsr); 342145132Sanholt } 343145132Sanholt 344207066Srnoland DRM_UNLOCK(); 345207066Srnoland if (map->handle) 346207066Srnoland free_unr(dev->map_unrhdr, (unsigned long)map->handle >> 347207066Srnoland DRM_MAP_HANDLE_SHIFT); 348207066Srnoland DRM_LOCK(); 349207066Srnoland 350183833Srnoland free(map, DRM_MEM_MAPS); 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; 361183573Srnoland struct drm_map *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 } 393183833Srnoland free(entry->seglist, DRM_MEM_SEGS); 394145132Sanholt 395145132Sanholt entry->seg_count = 0; 396145132Sanholt } 397145132Sanholt 398145132Sanholt if (entry->buf_count) { 399145132Sanholt for (i = 0; i < entry->buf_count; i++) { 400183833Srnoland free(entry->buflist[i].dev_private, DRM_MEM_BUFS); 401145132Sanholt } 402183833Srnoland free(entry->buflist, DRM_MEM_BUFS); 403145132Sanholt 404145132Sanholt entry->buf_count = 0; 405145132Sanholt } 406145132Sanholt} 407145132Sanholt 408183573Srnolandstatic int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *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) 432183573Srnoland ? 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 439183573Srnoland DRM_DEBUG("count: %d\n", count); 440183573Srnoland DRM_DEBUG("order: %d\n", order); 441183573Srnoland DRM_DEBUG("size: %d\n", size); 442183573Srnoland DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset); 443183573Srnoland DRM_DEBUG("alignment: %d\n", alignment); 444183573Srnoland DRM_DEBUG("page_order: %d\n", page_order); 445183573Srnoland 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 469183833Srnoland entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 470145132Sanholt M_NOWAIT | M_ZERO); 471183573Srnoland if (!entry->buflist) { 472182080Srnoland return ENOMEM; 473145132Sanholt } 474145132Sanholt 475145132Sanholt entry->buf_size = size; 476145132Sanholt entry->page_order = page_order; 477145132Sanholt 478145132Sanholt offset = 0; 479145132Sanholt 480183573Srnoland 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 494183573Srnoland buf->dev_priv_size = dev->driver->buf_priv_size; 495183833Srnoland buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 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 509183573Srnoland DRM_DEBUG("byte_count: %d\n", byte_count); 510145132Sanholt 511145132Sanholt temp_buflist = realloc(dma->buflist, 512183833Srnoland (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 513183833Srnoland DRM_MEM_BUFS, 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 521183573Srnoland 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 528183573Srnoland DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 529183573Srnoland 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 539183573Srnolandstatic int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *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 561183573Srnoland DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", 562183573Srnoland request->count, request->size, size, order); 563145132Sanholt 564145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 565183573Srnoland ? 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 571183833Srnoland entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 572145132Sanholt M_NOWAIT | M_ZERO); 573183833Srnoland entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, 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)) * 580183833Srnoland sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT); 581145132Sanholt 582145132Sanholt if (entry->buflist == NULL || entry->seglist == NULL || 583152909Sanholt temp_pagelist == NULL) { 584183833Srnoland free(temp_pagelist, DRM_MEM_PAGES); 585183833Srnoland free(entry->seglist, DRM_MEM_SEGS); 586183833Srnoland free(entry->buflist, DRM_MEM_BUFS); 587182080Srnoland return ENOMEM; 588145132Sanholt } 589183573Srnoland 590145132Sanholt memcpy(temp_pagelist, dma->pagelist, dma->page_count * 591145132Sanholt sizeof(*dma->pagelist)); 592145132Sanholt 593183573Srnoland DRM_DEBUG("pagelist: %d entries\n", 594183573Srnoland dma->page_count + (count << page_order)); 595145132Sanholt 596145132Sanholt entry->buf_size = size; 597145132Sanholt entry->page_order = page_order; 598145132Sanholt byte_count = 0; 599145132Sanholt page_count = 0; 600145132Sanholt 601183573Srnoland while (entry->buf_count < count) { 602182883Srnoland DRM_SPINUNLOCK(&dev->dma_lock); 603152909Sanholt drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 604152909Sanholt 0xfffffffful); 605182883Srnoland DRM_SPINLOCK(&dev->dma_lock); 606152909Sanholt if (dmah == NULL) { 607145132Sanholt /* Set count correctly so we free the proper amount. */ 608145132Sanholt entry->buf_count = count; 609145132Sanholt entry->seg_count = count; 610145132Sanholt drm_cleanup_buf_error(dev, entry); 611183833Srnoland free(temp_pagelist, DRM_MEM_PAGES); 612182080Srnoland return ENOMEM; 613145132Sanholt } 614152909Sanholt 615152909Sanholt entry->seglist[entry->seg_count++] = dmah; 616183573Srnoland for (i = 0; i < (1 << page_order); i++) { 617183573Srnoland DRM_DEBUG("page %d @ %p\n", 618183573Srnoland dma->page_count + page_count, 619183573Srnoland (char *)dmah->vaddr + PAGE_SIZE * i); 620145132Sanholt temp_pagelist[dma->page_count + page_count++] = 621152909Sanholt (long)dmah->vaddr + PAGE_SIZE * i; 622145132Sanholt } 623183573Srnoland for (offset = 0; 624183573Srnoland offset + size <= total && entry->buf_count < count; 625183573Srnoland offset += alignment, ++entry->buf_count) { 626145132Sanholt buf = &entry->buflist[entry->buf_count]; 627145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 628145132Sanholt buf->total = alignment; 629145132Sanholt buf->order = order; 630145132Sanholt buf->used = 0; 631145132Sanholt buf->offset = (dma->byte_count + byte_count + offset); 632152909Sanholt buf->address = ((char *)dmah->vaddr + offset); 633152909Sanholt buf->bus_address = dmah->busaddr + offset; 634145132Sanholt buf->next = NULL; 635145132Sanholt buf->pending = 0; 636182080Srnoland buf->file_priv = NULL; 637145132Sanholt 638183573Srnoland buf->dev_priv_size = dev->driver->buf_priv_size; 639183833Srnoland buf->dev_private = malloc(buf->dev_priv_size, 640183833Srnoland DRM_MEM_BUFS, M_NOWAIT | M_ZERO); 641145132Sanholt if (buf->dev_private == NULL) { 642145132Sanholt /* Set count correctly so we free the proper amount. */ 643145132Sanholt entry->buf_count = count; 644145132Sanholt entry->seg_count = count; 645145132Sanholt drm_cleanup_buf_error(dev, entry); 646183833Srnoland free(temp_pagelist, DRM_MEM_PAGES); 647182080Srnoland return ENOMEM; 648145132Sanholt } 649145132Sanholt 650183573Srnoland DRM_DEBUG("buffer %d @ %p\n", 651183573Srnoland entry->buf_count, buf->address); 652145132Sanholt } 653145132Sanholt byte_count += PAGE_SIZE << page_order; 654145132Sanholt } 655145132Sanholt 656145132Sanholt temp_buflist = realloc(dma->buflist, 657183833Srnoland (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 658183833Srnoland DRM_MEM_BUFS, M_NOWAIT); 659145132Sanholt if (temp_buflist == NULL) { 660145132Sanholt /* Free the entry because it isn't valid */ 661145132Sanholt drm_cleanup_buf_error(dev, entry); 662183833Srnoland free(temp_pagelist, DRM_MEM_PAGES); 663182080Srnoland return ENOMEM; 664145132Sanholt } 665145132Sanholt dma->buflist = temp_buflist; 666145132Sanholt 667183573Srnoland for (i = 0; i < entry->buf_count; i++) { 668145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 669145132Sanholt } 670145132Sanholt 671145132Sanholt /* No allocations failed, so now we can replace the orginal pagelist 672145132Sanholt * with the new one. 673145132Sanholt */ 674183833Srnoland free(dma->pagelist, DRM_MEM_PAGES); 675145132Sanholt dma->pagelist = temp_pagelist; 676145132Sanholt 677145132Sanholt dma->buf_count += entry->buf_count; 678145132Sanholt dma->seg_count += entry->seg_count; 679145132Sanholt dma->page_count += entry->seg_count << page_order; 680145132Sanholt dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 681145132Sanholt 682145132Sanholt request->count = entry->buf_count; 683145132Sanholt request->size = size; 684145132Sanholt 685145132Sanholt return 0; 686145132Sanholt 687145132Sanholt} 688145132Sanholt 689183573Srnolandstatic int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 690145132Sanholt{ 691145132Sanholt drm_device_dma_t *dma = dev->dma; 692145132Sanholt drm_buf_entry_t *entry; 693145132Sanholt drm_buf_t *buf; 694145132Sanholt unsigned long offset; 695145132Sanholt unsigned long agp_offset; 696145132Sanholt int count; 697145132Sanholt int order; 698145132Sanholt int size; 699145132Sanholt int alignment; 700145132Sanholt int page_order; 701145132Sanholt int total; 702145132Sanholt int byte_count; 703145132Sanholt int i; 704145132Sanholt drm_buf_t **temp_buflist; 705145132Sanholt 706145132Sanholt count = request->count; 707145132Sanholt order = drm_order(request->size); 708145132Sanholt size = 1 << order; 709145132Sanholt 710145132Sanholt alignment = (request->flags & _DRM_PAGE_ALIGN) 711183573Srnoland ? round_page(size) : size; 712145132Sanholt page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 713145132Sanholt total = PAGE_SIZE << page_order; 714145132Sanholt 715145132Sanholt byte_count = 0; 716145132Sanholt agp_offset = request->agp_start; 717145132Sanholt 718183573Srnoland DRM_DEBUG("count: %d\n", count); 719183573Srnoland DRM_DEBUG("order: %d\n", order); 720183573Srnoland DRM_DEBUG("size: %d\n", size); 721183573Srnoland DRM_DEBUG("agp_offset: %ld\n", agp_offset); 722183573Srnoland DRM_DEBUG("alignment: %d\n", alignment); 723183573Srnoland DRM_DEBUG("page_order: %d\n", page_order); 724183573Srnoland DRM_DEBUG("total: %d\n", total); 725145132Sanholt 726145132Sanholt entry = &dma->bufs[order]; 727145132Sanholt 728183833Srnoland entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 729145132Sanholt M_NOWAIT | M_ZERO); 730145132Sanholt if (entry->buflist == NULL) 731182080Srnoland return ENOMEM; 732145132Sanholt 733145132Sanholt entry->buf_size = size; 734145132Sanholt entry->page_order = page_order; 735145132Sanholt 736145132Sanholt offset = 0; 737145132Sanholt 738183573Srnoland while (entry->buf_count < count) { 739145132Sanholt buf = &entry->buflist[entry->buf_count]; 740145132Sanholt buf->idx = dma->buf_count + entry->buf_count; 741145132Sanholt buf->total = alignment; 742145132Sanholt buf->order = order; 743145132Sanholt buf->used = 0; 744145132Sanholt 745145132Sanholt buf->offset = (dma->byte_count + offset); 746145132Sanholt buf->bus_address = agp_offset + offset; 747207067Srnoland buf->address = (void *)(agp_offset + offset + dev->sg->vaddr); 748145132Sanholt buf->next = NULL; 749145132Sanholt buf->pending = 0; 750182080Srnoland buf->file_priv = NULL; 751145132Sanholt 752183573Srnoland buf->dev_priv_size = dev->driver->buf_priv_size; 753183833Srnoland buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 754145132Sanholt M_NOWAIT | M_ZERO); 755145132Sanholt if (buf->dev_private == NULL) { 756145132Sanholt /* Set count correctly so we free the proper amount. */ 757145132Sanholt entry->buf_count = count; 758145132Sanholt drm_cleanup_buf_error(dev, entry); 759182080Srnoland return ENOMEM; 760145132Sanholt } 761145132Sanholt 762183573Srnoland DRM_DEBUG("buffer %d @ %p\n", 763183573Srnoland entry->buf_count, buf->address); 764145132Sanholt 765145132Sanholt offset += alignment; 766145132Sanholt entry->buf_count++; 767145132Sanholt byte_count += PAGE_SIZE << page_order; 768145132Sanholt } 769145132Sanholt 770183573Srnoland DRM_DEBUG("byte_count: %d\n", byte_count); 771145132Sanholt 772145132Sanholt temp_buflist = realloc(dma->buflist, 773183833Srnoland (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 774183833Srnoland DRM_MEM_BUFS, M_NOWAIT); 775145132Sanholt if (temp_buflist == NULL) { 776145132Sanholt /* Free the entry because it isn't valid */ 777145132Sanholt drm_cleanup_buf_error(dev, entry); 778182080Srnoland return ENOMEM; 779145132Sanholt } 780145132Sanholt dma->buflist = temp_buflist; 781145132Sanholt 782183573Srnoland for (i = 0; i < entry->buf_count; i++) { 783145132Sanholt dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 784145132Sanholt } 785145132Sanholt 786145132Sanholt dma->buf_count += entry->buf_count; 787145132Sanholt dma->byte_count += byte_count; 788145132Sanholt 789183573Srnoland DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 790183573Srnoland DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 791145132Sanholt 792145132Sanholt request->count = entry->buf_count; 793145132Sanholt request->size = size; 794145132Sanholt 795145132Sanholt dma->flags = _DRM_DMA_USE_SG; 796145132Sanholt 797145132Sanholt return 0; 798145132Sanholt} 799145132Sanholt 800183573Srnolandint drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 801145132Sanholt{ 802152909Sanholt int order, ret; 803145132Sanholt 804152909Sanholt if (request->count < 0 || request->count > 4096) 805182080Srnoland return EINVAL; 806152909Sanholt 807152909Sanholt order = drm_order(request->size); 808152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 809182080Srnoland return EINVAL; 810145132Sanholt 811182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 812182080Srnoland 813152909Sanholt /* No more allocations after first buffer-using ioctl. */ 814152909Sanholt if (dev->buf_use != 0) { 815152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 816182080Srnoland return EBUSY; 817152909Sanholt } 818152909Sanholt /* No more than one allocation per order */ 819152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 820152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 821182080Srnoland return ENOMEM; 822152909Sanholt } 823152909Sanholt 824152909Sanholt ret = drm_do_addbufs_agp(dev, request); 825152909Sanholt 826152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 827152909Sanholt 828152909Sanholt return ret; 829152909Sanholt} 830152909Sanholt 831183573Srnolandint drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 832152909Sanholt{ 833152909Sanholt int order, ret; 834152909Sanholt 835152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 836182080Srnoland return EACCES; 837152909Sanholt 838152909Sanholt if (request->count < 0 || request->count > 4096) 839182080Srnoland return EINVAL; 840182080Srnoland 841152909Sanholt order = drm_order(request->size); 842145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 843182080Srnoland return EINVAL; 844145132Sanholt 845182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 846182080Srnoland 847152909Sanholt /* No more allocations after first buffer-using ioctl. */ 848152909Sanholt if (dev->buf_use != 0) { 849152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 850182080Srnoland return EBUSY; 851152909Sanholt } 852152909Sanholt /* No more than one allocation per order */ 853152909Sanholt if (dev->dma->bufs[order].buf_count != 0) { 854152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 855182080Srnoland return ENOMEM; 856152909Sanholt } 857152909Sanholt 858152909Sanholt ret = drm_do_addbufs_sg(dev, request); 859152909Sanholt 860152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 861152909Sanholt 862152909Sanholt return ret; 863152909Sanholt} 864152909Sanholt 865183573Srnolandint drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 866152909Sanholt{ 867152909Sanholt int order, ret; 868152909Sanholt 869152909Sanholt if (!DRM_SUSER(DRM_CURPROC)) 870182080Srnoland return EACCES; 871152909Sanholt 872152909Sanholt if (request->count < 0 || request->count > 4096) 873182080Srnoland return EINVAL; 874182080Srnoland 875152909Sanholt order = drm_order(request->size); 876152909Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 877182080Srnoland return EINVAL; 878152909Sanholt 879182080Srnoland DRM_SPINLOCK(&dev->dma_lock); 880182080Srnoland 881145132Sanholt /* No more allocations after first buffer-using ioctl. */ 882145132Sanholt if (dev->buf_use != 0) { 883145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 884182080Srnoland return EBUSY; 885145132Sanholt } 886145132Sanholt /* No more than one allocation per order */ 887145132Sanholt if (dev->dma->bufs[order].buf_count != 0) { 888145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 889182080Srnoland return ENOMEM; 890145132Sanholt } 891145132Sanholt 892152909Sanholt ret = drm_do_addbufs_pci(dev, request); 893152909Sanholt 894152909Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 895152909Sanholt 896152909Sanholt return ret; 897152909Sanholt} 898152909Sanholt 899189099Srnolandint drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 900152909Sanholt{ 901183573Srnoland struct drm_buf_desc *request = data; 902152909Sanholt int err; 903152909Sanholt 904182080Srnoland if (request->flags & _DRM_AGP_BUFFER) 905182080Srnoland err = drm_addbufs_agp(dev, request); 906182080Srnoland else if (request->flags & _DRM_SG_BUFFER) 907182080Srnoland err = drm_addbufs_sg(dev, request); 908145132Sanholt else 909182080Srnoland err = drm_addbufs_pci(dev, request); 910145132Sanholt 911145132Sanholt return err; 912145132Sanholt} 913145132Sanholt 914182080Srnolandint drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 915145132Sanholt{ 916145132Sanholt drm_device_dma_t *dma = dev->dma; 917183573Srnoland struct drm_buf_info *request = data; 918145132Sanholt int i; 919145132Sanholt int count; 920145132Sanholt int retcode = 0; 921145132Sanholt 922145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 923145132Sanholt ++dev->buf_use; /* Can't allocate more after this call */ 924145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 925145132Sanholt 926183573Srnoland for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 927183573Srnoland if (dma->bufs[i].buf_count) 928183573Srnoland ++count; 929145132Sanholt } 930145132Sanholt 931183573Srnoland DRM_DEBUG("count = %d\n", count); 932145132Sanholt 933183573Srnoland if (request->count >= count) { 934183573Srnoland for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 935183573Srnoland if (dma->bufs[i].buf_count) { 936183573Srnoland struct drm_buf_desc from; 937145132Sanholt 938331987Sgordon memset(&from, 0, sizeof(from)); 939145132Sanholt from.count = dma->bufs[i].buf_count; 940145132Sanholt from.size = dma->bufs[i].buf_size; 941145132Sanholt from.low_mark = dma->bufs[i].freelist.low_mark; 942145132Sanholt from.high_mark = dma->bufs[i].freelist.high_mark; 943145132Sanholt 944182080Srnoland if (DRM_COPY_TO_USER(&request->list[count], &from, 945183573Srnoland sizeof(struct drm_buf_desc)) != 0) { 946182080Srnoland retcode = EFAULT; 947145132Sanholt break; 948145132Sanholt } 949145132Sanholt 950183573Srnoland DRM_DEBUG("%d %d %d %d %d\n", 951183573Srnoland i, dma->bufs[i].buf_count, 952183573Srnoland dma->bufs[i].buf_size, 953183573Srnoland dma->bufs[i].freelist.low_mark, 954183573Srnoland dma->bufs[i].freelist.high_mark); 955145132Sanholt ++count; 956145132Sanholt } 957145132Sanholt } 958145132Sanholt } 959182080Srnoland request->count = count; 960145132Sanholt 961145132Sanholt return retcode; 962145132Sanholt} 963145132Sanholt 964182080Srnolandint drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 965145132Sanholt{ 966145132Sanholt drm_device_dma_t *dma = dev->dma; 967183573Srnoland struct drm_buf_desc *request = data; 968145132Sanholt int order; 969145132Sanholt 970183573Srnoland DRM_DEBUG("%d, %d, %d\n", 971183573Srnoland request->size, request->low_mark, request->high_mark); 972145132Sanholt 973145132Sanholt 974182080Srnoland order = drm_order(request->size); 975145132Sanholt if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 976182080Srnoland request->low_mark < 0 || request->high_mark < 0) { 977182080Srnoland return EINVAL; 978145132Sanholt } 979145132Sanholt 980145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 981182080Srnoland if (request->low_mark > dma->bufs[order].buf_count || 982182080Srnoland request->high_mark > dma->bufs[order].buf_count) { 983182080Srnoland DRM_SPINUNLOCK(&dev->dma_lock); 984182080Srnoland return EINVAL; 985145132Sanholt } 986145132Sanholt 987182080Srnoland dma->bufs[order].freelist.low_mark = request->low_mark; 988182080Srnoland dma->bufs[order].freelist.high_mark = request->high_mark; 989145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 990145132Sanholt 991145132Sanholt return 0; 992145132Sanholt} 993145132Sanholt 994182080Srnolandint drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 995145132Sanholt{ 996145132Sanholt drm_device_dma_t *dma = dev->dma; 997183573Srnoland struct drm_buf_free *request = data; 998145132Sanholt int i; 999145132Sanholt int idx; 1000145132Sanholt drm_buf_t *buf; 1001145132Sanholt int retcode = 0; 1002145132Sanholt 1003183573Srnoland DRM_DEBUG("%d\n", request->count); 1004145132Sanholt 1005145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 1006183573Srnoland for (i = 0; i < request->count; i++) { 1007182080Srnoland if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { 1008182080Srnoland retcode = EFAULT; 1009145132Sanholt break; 1010145132Sanholt } 1011183573Srnoland if (idx < 0 || idx >= dma->buf_count) { 1012183573Srnoland DRM_ERROR("Index %d (of %d max)\n", 1013183573Srnoland idx, dma->buf_count - 1); 1014182080Srnoland retcode = EINVAL; 1015145132Sanholt break; 1016145132Sanholt } 1017145132Sanholt buf = dma->buflist[idx]; 1018183573Srnoland if (buf->file_priv != file_priv) { 1019145132Sanholt DRM_ERROR("Process %d freeing buffer not owned\n", 1020183573Srnoland DRM_CURRENTPID); 1021182080Srnoland retcode = EINVAL; 1022145132Sanholt break; 1023145132Sanholt } 1024145132Sanholt drm_free_buffer(dev, buf); 1025145132Sanholt } 1026145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1027145132Sanholt 1028145132Sanholt return retcode; 1029145132Sanholt} 1030145132Sanholt 1031182080Srnolandint drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 1032145132Sanholt{ 1033145132Sanholt drm_device_dma_t *dma = dev->dma; 1034145132Sanholt int retcode = 0; 1035145132Sanholt const int zero = 0; 1036145132Sanholt vm_offset_t address; 1037145132Sanholt struct vmspace *vms; 1038145132Sanholt vm_ooffset_t foff; 1039145132Sanholt vm_size_t size; 1040145132Sanholt vm_offset_t vaddr; 1041183573Srnoland struct drm_buf_map *request = data; 1042145132Sanholt int i; 1043145132Sanholt 1044182080Srnoland vms = DRM_CURPROC->td_proc->p_vmspace; 1045145132Sanholt 1046145132Sanholt DRM_SPINLOCK(&dev->dma_lock); 1047145132Sanholt dev->buf_use++; /* Can't allocate more after this call */ 1048145132Sanholt DRM_SPINUNLOCK(&dev->dma_lock); 1049145132Sanholt 1050182080Srnoland if (request->count < dma->buf_count) 1051145132Sanholt goto done; 1052145132Sanholt 1053183573Srnoland if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || 1054183573Srnoland (drm_core_check_feature(dev, DRIVER_SG) && 1055183573Srnoland (dma->flags & _DRM_DMA_USE_SG))) { 1056145132Sanholt drm_local_map_t *map = dev->agp_buffer_map; 1057145132Sanholt 1058145132Sanholt if (map == NULL) { 1059145132Sanholt retcode = EINVAL; 1060145132Sanholt goto done; 1061145132Sanholt } 1062145132Sanholt size = round_page(map->size); 1063207066Srnoland foff = (unsigned long)map->handle; 1064145132Sanholt } else { 1065145132Sanholt size = round_page(dma->byte_count), 1066145132Sanholt foff = 0; 1067145132Sanholt } 1068145132Sanholt 1069145132Sanholt vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1070145132Sanholt#if __FreeBSD_version >= 600023 1071145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1072189561Srnoland VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, 1073189561Srnoland dev->devnode, foff); 1074145132Sanholt#else 1075145132Sanholt retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1076189561Srnoland VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, 1077189561Srnoland SLIST_FIRST(&dev->devnode->si_hlist), foff); 1078145132Sanholt#endif 1079145132Sanholt if (retcode) 1080145132Sanholt goto done; 1081145132Sanholt 1082182080Srnoland request->virtual = (void *)vaddr; 1083145132Sanholt 1084183573Srnoland for (i = 0; i < dma->buf_count; i++) { 1085182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].idx, 1086182080Srnoland &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 1087145132Sanholt retcode = EFAULT; 1088145132Sanholt goto done; 1089145132Sanholt } 1090182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].total, 1091182080Srnoland &dma->buflist[i]->total, sizeof(request->list[0].total))) { 1092145132Sanholt retcode = EFAULT; 1093145132Sanholt goto done; 1094145132Sanholt } 1095182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].used, &zero, 1096145132Sanholt sizeof(zero))) { 1097145132Sanholt retcode = EFAULT; 1098145132Sanholt goto done; 1099145132Sanholt } 1100145132Sanholt address = vaddr + dma->buflist[i]->offset; /* *** */ 1101182080Srnoland if (DRM_COPY_TO_USER(&request->list[i].address, &address, 1102145132Sanholt sizeof(address))) { 1103145132Sanholt retcode = EFAULT; 1104145132Sanholt goto done; 1105145132Sanholt } 1106145132Sanholt } 1107145132Sanholt 1108145132Sanholt done: 1109182080Srnoland request->count = dma->buf_count; 1110145132Sanholt 1111183573Srnoland DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); 1112145132Sanholt 1113182080Srnoland return retcode; 1114145132Sanholt} 1115183573Srnoland 1116183573Srnoland/* 1117183573Srnoland * Compute order. Can be made faster. 1118183573Srnoland */ 1119183573Srnolandint drm_order(unsigned long size) 1120183573Srnoland{ 1121183573Srnoland int order; 1122183573Srnoland 1123183603Srnoland if (size == 0) 1124183603Srnoland return 0; 1125183573Srnoland 1126189908Srnoland order = flsl(size) - 1; 1127183603Srnoland if (size & ~(1ul << order)) 1128183573Srnoland ++order; 1129183573Srnoland 1130183573Srnoland return order; 1131183573Srnoland} 1132