drm_bufs.c revision 207066
1265236Sken/*- 2283990Sslm * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 3283990Sslm * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 4265236Sken * All Rights Reserved. 5265236Sken * 6265236Sken * Permission is hereby granted, free of charge, to any person obtaining a 7265236Sken * copy of this software and associated documentation files (the "Software"), 8265236Sken * to deal in the Software without restriction, including without limitation 9265236Sken * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10265236Sken * and/or sell copies of the Software, and to permit persons to whom the 11265236Sken * Software is furnished to do so, subject to the following conditions: 12265236Sken * 13265236Sken * The above copyright notice and this permission notice (including the next 14265236Sken * paragraph) shall be included in all copies or substantial portions of the 15265236Sken * Software. 16265236Sken * 17265236Sken * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18265236Sken * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19265236Sken * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20265236Sken * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21265236Sken * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22265236Sken * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23265236Sken * OTHER DEALINGS IN THE SOFTWARE. 24265236Sken * 25265236Sken * Authors: 26265236Sken * Rickard E. (Rik) Faith <faith@valinux.com> 27283990Sslm * Gareth Hughes <gareth@valinux.com> 28265236Sken * 29265236Sken */ 30265236Sken 31265236Sken#include <sys/cdefs.h> 32265236Sken__FBSDID("$FreeBSD: head/sys/dev/drm/drm_bufs.c 207066 2010-04-22 18:21:25Z rnoland $"); 33283990Sslm 34265236Sken/** @file drm_bufs.c 35265236Sken * Implementation of the ioctls for setup of DRM mappings and DMA buffers. 36265236Sken */ 37265236Sken 38265236Sken#include "dev/pci/pcireg.h" 39265236Sken 40265236Sken#include "dev/drm/drmP.h" 41265236Sken 42265236Sken/* Allocation of PCI memory resources (framebuffer, registers, etc.) for 43265236Sken * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual 44265236Sken * address for accessing them. Cleaned up at unload. 45265236Sken */ 46265236Skenstatic int drm_alloc_resource(struct drm_device *dev, int resource) 47265236Sken{ 48265236Sken struct resource *res; 49265236Sken int rid; 50265236Sken 51265236Sken DRM_SPINLOCK_ASSERT(&dev->dev_lock); 52265236Sken 53265236Sken if (resource >= DRM_MAX_PCI_RESOURCE) { 54265236Sken DRM_ERROR("Resource %d too large\n", resource); 55265236Sken return 1; 56265236Sken } 57265236Sken 58265236Sken if (dev->pcir[resource] != NULL) { 59265236Sken return 0; 60265236Sken } 61265236Sken 62265236Sken DRM_UNLOCK(); 63265236Sken rid = PCIR_BAR(resource); 64265236Sken res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid, 65265236Sken RF_SHAREABLE); 66265236Sken DRM_LOCK(); 67265236Sken if (res == NULL) { 68265236Sken DRM_ERROR("Couldn't find resource 0x%x\n", resource); 69265236Sken return 1; 70265236Sken } 71265236Sken 72265236Sken if (dev->pcir[resource] == NULL) { 73265236Sken dev->pcirid[resource] = rid; 74265236Sken dev->pcir[resource] = res; 75265236Sken } 76265236Sken 77265236Sken return 0; 78265236Sken} 79265236Sken 80265236Skenunsigned long drm_get_resource_start(struct drm_device *dev, 81265236Sken unsigned int resource) 82265236Sken{ 83265236Sken if (drm_alloc_resource(dev, resource) != 0) 84265236Sken return 0; 85265236Sken 86265236Sken return rman_get_start(dev->pcir[resource]); 87265236Sken} 88265236Sken 89265236Skenunsigned long drm_get_resource_len(struct drm_device *dev, 90265236Sken unsigned int resource) 91265236Sken{ 92265236Sken if (drm_alloc_resource(dev, resource) != 0) 93265236Sken return 0; 94265236Sken 95265236Sken return rman_get_size(dev->pcir[resource]); 96265236Sken} 97265236Sken 98265236Skenint drm_addmap(struct drm_device * dev, unsigned long offset, 99265236Sken unsigned long size, 100265236Sken enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr) 101265236Sken{ 102265236Sken drm_local_map_t *map; 103265236Sken int align; 104265236Sken /*drm_agp_mem_t *entry; 105265236Sken int valid;*/ 106265236Sken 107265236Sken /* Only allow shared memory to be removable since we only keep enough 108265236Sken * book keeping information about shared memory to allow for removal 109283990Sslm * when processes fork. 110283990Sslm */ 111283990Sslm if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { 112265236Sken DRM_ERROR("Requested removable map for non-DRM_SHM\n"); 113265236Sken return EINVAL; 114265236Sken } 115265236Sken if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { 116265236Sken DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", 117265236Sken offset, size); 118265236Sken return EINVAL; 119265236Sken } 120265236Sken if (offset + size < offset) { 121265236Sken DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", 122283990Sslm offset, size); 123265236Sken return EINVAL; 124283990Sslm } 125265236Sken 126265236Sken DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, 127265236Sken size, type); 128265236Sken 129265236Sken /* Check if this is just another version of a kernel-allocated map, and 130265236Sken * just hand that back if so. 131265236Sken */ 132265236Sken if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || 133265236Sken type == _DRM_SHM) { 134265236Sken TAILQ_FOREACH(map, &dev->maplist, link) { 135265236Sken if (map->type == type && (map->offset == offset || 136265236Sken (map->type == _DRM_SHM && 137265236Sken map->flags == _DRM_CONTAINS_LOCK))) { 138265236Sken map->size = size; 139265236Sken DRM_DEBUG("Found kernel map %d\n", type); 140265236Sken goto done; 141265236Sken } 142265236Sken } 143265236Sken } 144265236Sken DRM_UNLOCK(); 145265236Sken 146265236Sken /* Allocate a new map structure, fill it in, and do any type-specific 147265236Sken * initialization necessary. 148265236Sken */ 149265236Sken map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); 150265236Sken if (!map) { 151265236Sken DRM_LOCK(); 152265236Sken return ENOMEM; 153265236Sken } 154265236Sken 155265236Sken map->offset = offset; 156265236Sken map->size = size; 157265236Sken map->type = type; 158265236Sken map->flags = flags; 159265236Sken map->handle = (void *)((unsigned long)alloc_unr(dev->map_unrhdr) << 160265236Sken DRM_MAP_HANDLE_SHIFT); 161265236Sken 162265236Sken switch (map->type) { 163265236Sken case _DRM_REGISTERS: 164265236Sken map->virtual = drm_ioremap(dev, map); 165265236Sken if (!(map->flags & _DRM_WRITE_COMBINING)) 166265236Sken break; 167265236Sken /* FALLTHROUGH */ 168265236Sken case _DRM_FRAME_BUFFER: 169265236Sken if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) 170265236Sken map->mtrr = 1; 171265236Sken break; 172265236Sken case _DRM_SHM: 173265236Sken map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT); 174265236Sken DRM_DEBUG("%lu %d %p\n", 175265236Sken map->size, drm_order(map->size), map->virtual); 176265236Sken if (!map->virtual) { 177265236Sken free(map, DRM_MEM_MAPS); 178265236Sken DRM_LOCK(); 179265236Sken return ENOMEM; 180265236Sken } 181265236Sken map->offset = (unsigned long)map->virtual; 182265236Sken if (map->flags & _DRM_CONTAINS_LOCK) { 183265236Sken /* Prevent a 2nd X Server from creating a 2nd lock */ 184265236Sken DRM_LOCK(); 185265236Sken if (dev->lock.hw_lock != NULL) { 186265236Sken DRM_UNLOCK(); 187265236Sken free(map->virtual, DRM_MEM_MAPS); 188265236Sken free(map, DRM_MEM_MAPS); 189265236Sken return EBUSY; 190265236Sken } 191265236Sken dev->lock.hw_lock = map->virtual; /* Pointer to lock */ 192265236Sken DRM_UNLOCK(); 193265236Sken } 194265236Sken break; 195265236Sken case _DRM_AGP: 196265236Sken /*valid = 0;*/ 197265236Sken /* In some cases (i810 driver), user space may have already 198265236Sken * added the AGP base itself, because dev->agp->base previously 199265236Sken * only got set during AGP enable. So, only add the base 200265236Sken * address if the map's offset isn't already within the 201265236Sken * aperture. 202265236Sken */ 203265236Sken if (map->offset < dev->agp->base || 204265236Sken map->offset > dev->agp->base + 205265236Sken dev->agp->info.ai_aperture_size - 1) { 206265236Sken map->offset += dev->agp->base; 207265236Sken } 208265236Sken map->mtrr = dev->agp->mtrr; /* for getmap */ 209265236Sken /*for (entry = dev->agp->memory; entry; entry = entry->next) { 210265236Sken if ((map->offset >= entry->bound) && 211265236Sken (map->offset + map->size <= 212265236Sken entry->bound + entry->pages * PAGE_SIZE)) { 213265236Sken valid = 1; 214265236Sken break; 215265236Sken } 216265236Sken } 217265236Sken if (!valid) { 218265236Sken free(map, DRM_MEM_MAPS); 219265236Sken DRM_LOCK(); 220265236Sken return EACCES; 221265236Sken }*/ 222265236Sken break; 223265236Sken case _DRM_SCATTER_GATHER: 224265236Sken if (!dev->sg) { 225265236Sken free(map, DRM_MEM_MAPS); 226265236Sken DRM_LOCK(); 227265236Sken return EINVAL; 228265236Sken } 229265236Sken map->virtual = (void *)(dev->sg->handle + offset); 230265236Sken map->offset = dev->sg->handle + offset; 231265236Sken break; 232265236Sken case _DRM_CONSISTENT: 233265236Sken /* Unfortunately, we don't get any alignment specification from 234265236Sken * the caller, so we have to guess. drm_pci_alloc requires 235265236Sken * a power-of-two alignment, so try to align the bus address of 236265236Sken * the map to it size if possible, otherwise just assume 237265236Sken * PAGE_SIZE alignment. 238265236Sken */ 239265236Sken align = map->size; 240265236Sken if ((align & (align - 1)) != 0) 241265236Sken align = PAGE_SIZE; 242265236Sken map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); 243265236Sken if (map->dmah == NULL) { 244265236Sken free(map, DRM_MEM_MAPS); 245265236Sken DRM_LOCK(); 246265236Sken return ENOMEM; 247265236Sken } 248265236Sken map->virtual = map->dmah->vaddr; 249265236Sken map->offset = map->dmah->busaddr; 250265236Sken break; 251265236Sken default: 252265236Sken DRM_ERROR("Bad map type %d\n", map->type); 253265236Sken free(map, DRM_MEM_MAPS); 254265236Sken DRM_LOCK(); 255265236Sken return EINVAL; 256265236Sken } 257265236Sken 258265236Sken DRM_LOCK(); 259265236Sken TAILQ_INSERT_TAIL(&dev->maplist, map, link); 260265236Sken 261265236Skendone: 262265236Sken /* Jumped to, with lock held, when a kernel map is found. */ 263265236Sken 264265236Sken DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, 265265236Sken map->size); 266265236Sken 267265236Sken *map_ptr = map; 268265236Sken 269265236Sken return 0; 270265236Sken} 271265236Sken 272265236Skenint drm_addmap_ioctl(struct drm_device *dev, void *data, 273265236Sken struct drm_file *file_priv) 274265236Sken{ 275265236Sken struct drm_map *request = data; 276265236Sken drm_local_map_t *map; 277265236Sken int err; 278265236Sken 279265236Sken if (!(dev->flags & (FREAD|FWRITE))) 280265236Sken return EACCES; /* Require read/write */ 281265236Sken 282265236Sken if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) 283265236Sken return EACCES; 284265236Sken 285265236Sken DRM_LOCK(); 286265236Sken err = drm_addmap(dev, request->offset, request->size, request->type, 287265236Sken request->flags, &map); 288265236Sken DRM_UNLOCK(); 289265236Sken if (err != 0) 290265236Sken return err; 291265236Sken 292265236Sken request->offset = map->offset; 293265236Sken request->size = map->size; 294265236Sken request->type = map->type; 295265236Sken request->flags = map->flags; 296265236Sken request->mtrr = map->mtrr; 297265236Sken request->handle = (void *)map->handle; 298265236Sken 299265236Sken return 0; 300265236Sken} 301265236Sken 302265236Skenvoid drm_rmmap(struct drm_device *dev, drm_local_map_t *map) 303265236Sken{ 304265236Sken DRM_SPINLOCK_ASSERT(&dev->dev_lock); 305265236Sken 306265236Sken if (map == NULL) 307265236Sken return; 308265236Sken 309265236Sken TAILQ_REMOVE(&dev->maplist, map, link); 310265236Sken 311265236Sken switch (map->type) { 312265236Sken case _DRM_REGISTERS: 313265236Sken if (map->bsr == NULL) 314265236Sken drm_ioremapfree(map); 315265236Sken /* FALLTHROUGH */ 316265236Sken case _DRM_FRAME_BUFFER: 317265236Sken if (map->mtrr) { 318265236Sken int __unused retcode; 319265236Sken 320265236Sken retcode = drm_mtrr_del(0, map->offset, map->size, 321265236Sken DRM_MTRR_WC); 322265236Sken DRM_DEBUG("mtrr_del = %d\n", retcode); 323265236Sken } 324265236Sken break; 325265236Sken case _DRM_SHM: 326265236Sken free(map->virtual, DRM_MEM_MAPS); 327265236Sken break; 328265236Sken case _DRM_AGP: 329265236Sken case _DRM_SCATTER_GATHER: 330265236Sken break; 331265236Sken case _DRM_CONSISTENT: 332283990Sslm drm_pci_free(dev, map->dmah); 333265236Sken break; 334265236Sken default: 335265236Sken DRM_ERROR("Bad map type %d\n", map->type); 336265236Sken break; 337265236Sken } 338265236Sken 339265236Sken if (map->bsr != NULL) { 340265236Sken bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, 341265236Sken map->bsr); 342265236Sken } 343265236Sken 344265236Sken DRM_UNLOCK(); 345265236Sken if (map->handle) 346265236Sken free_unr(dev->map_unrhdr, (unsigned long)map->handle >> 347265236Sken DRM_MAP_HANDLE_SHIFT); 348265236Sken DRM_LOCK(); 349265236Sken 350265236Sken free(map, DRM_MEM_MAPS); 351265236Sken} 352265236Sken 353265236Sken/* Remove a map private from list and deallocate resources if the mapping 354265236Sken * isn't in use. 355265236Sken */ 356265236Sken 357283990Sslmint drm_rmmap_ioctl(struct drm_device *dev, void *data, 358283990Sslm struct drm_file *file_priv) 359283990Sslm{ 360265236Sken drm_local_map_t *map; 361265236Sken struct drm_map *request = data; 362265236Sken 363265236Sken DRM_LOCK(); 364265236Sken TAILQ_FOREACH(map, &dev->maplist, link) { 365265236Sken if (map->handle == request->handle && 366265236Sken map->flags & _DRM_REMOVABLE) 367283990Sslm break; 368265236Sken } 369265236Sken 370265236Sken /* No match found. */ 371265236Sken if (map == NULL) { 372265236Sken DRM_UNLOCK(); 373265236Sken return EINVAL; 374265236Sken } 375265236Sken 376265236Sken drm_rmmap(dev, map); 377265236Sken 378265236Sken DRM_UNLOCK(); 379265236Sken 380265236Sken return 0; 381265236Sken} 382265236Sken 383265236Sken 384265236Skenstatic void drm_cleanup_buf_error(struct drm_device *dev, 385265236Sken drm_buf_entry_t *entry) 386265236Sken{ 387265236Sken int i; 388265236Sken 389265236Sken if (entry->seg_count) { 390265236Sken for (i = 0; i < entry->seg_count; i++) { 391265236Sken drm_pci_free(dev, entry->seglist[i]); 392265236Sken } 393265236Sken free(entry->seglist, DRM_MEM_SEGS); 394265236Sken 395265236Sken entry->seg_count = 0; 396265236Sken } 397265236Sken 398265236Sken if (entry->buf_count) { 399265236Sken for (i = 0; i < entry->buf_count; i++) { 400265236Sken free(entry->buflist[i].dev_private, DRM_MEM_BUFS); 401265236Sken } 402265236Sken free(entry->buflist, DRM_MEM_BUFS); 403265236Sken 404265236Sken entry->buf_count = 0; 405265236Sken } 406265236Sken} 407265236Sken 408265236Skenstatic int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 409265236Sken{ 410265236Sken drm_device_dma_t *dma = dev->dma; 411265236Sken drm_buf_entry_t *entry; 412265236Sken /*drm_agp_mem_t *agp_entry; 413265236Sken int valid*/ 414265236Sken drm_buf_t *buf; 415265236Sken unsigned long offset; 416265236Sken unsigned long agp_offset; 417265236Sken int count; 418265236Sken int order; 419265236Sken int size; 420265236Sken int alignment; 421265236Sken int page_order; 422265236Sken int total; 423265236Sken int byte_count; 424265236Sken int i; 425265236Sken drm_buf_t **temp_buflist; 426265236Sken 427265236Sken count = request->count; 428265236Sken order = drm_order(request->size); 429265236Sken size = 1 << order; 430265236Sken 431265236Sken alignment = (request->flags & _DRM_PAGE_ALIGN) 432265236Sken ? round_page(size) : size; 433265236Sken page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 434265236Sken total = PAGE_SIZE << page_order; 435265236Sken 436265236Sken byte_count = 0; 437265236Sken agp_offset = dev->agp->base + request->agp_start; 438265236Sken 439265236Sken DRM_DEBUG("count: %d\n", count); 440265236Sken DRM_DEBUG("order: %d\n", order); 441265236Sken DRM_DEBUG("size: %d\n", size); 442265236Sken DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset); 443265236Sken DRM_DEBUG("alignment: %d\n", alignment); 444265236Sken DRM_DEBUG("page_order: %d\n", page_order); 445265236Sken DRM_DEBUG("total: %d\n", total); 446265236Sken 447265236Sken /* Make sure buffers are located in AGP memory that we own */ 448265236Sken /* Breaks MGA due to drm_alloc_agp not setting up entries for the 449265236Sken * memory. Safe to ignore for now because these ioctls are still 450265236Sken * root-only. 451265236Sken */ 452265236Sken /*valid = 0; 453265236Sken for (agp_entry = dev->agp->memory; agp_entry; 454265236Sken agp_entry = agp_entry->next) { 455265236Sken if ((agp_offset >= agp_entry->bound) && 456265236Sken (agp_offset + total * count <= 457265236Sken agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { 458265236Sken valid = 1; 459265236Sken break; 460265236Sken } 461265236Sken } 462265236Sken if (!valid) { 463265236Sken DRM_DEBUG("zone invalid\n"); 464265236Sken return EINVAL; 465265236Sken }*/ 466265236Sken 467265236Sken entry = &dma->bufs[order]; 468265236Sken 469265236Sken entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 470265236Sken M_NOWAIT | M_ZERO); 471265236Sken if (!entry->buflist) { 472265236Sken return ENOMEM; 473265236Sken } 474265236Sken 475265236Sken entry->buf_size = size; 476265236Sken entry->page_order = page_order; 477265236Sken 478265236Sken offset = 0; 479265236Sken 480265236Sken while (entry->buf_count < count) { 481265236Sken buf = &entry->buflist[entry->buf_count]; 482265236Sken buf->idx = dma->buf_count + entry->buf_count; 483265236Sken buf->total = alignment; 484265236Sken buf->order = order; 485265236Sken buf->used = 0; 486265236Sken 487265236Sken buf->offset = (dma->byte_count + offset); 488265236Sken buf->bus_address = agp_offset + offset; 489265236Sken buf->address = (void *)(agp_offset + offset); 490265236Sken buf->next = NULL; 491265236Sken buf->pending = 0; 492265236Sken buf->file_priv = NULL; 493265236Sken 494265236Sken buf->dev_priv_size = dev->driver->buf_priv_size; 495265236Sken buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 496265236Sken M_NOWAIT | M_ZERO); 497265236Sken if (buf->dev_private == NULL) { 498265236Sken /* Set count correctly so we free the proper amount. */ 499265236Sken entry->buf_count = count; 500265236Sken drm_cleanup_buf_error(dev, entry); 501265236Sken return ENOMEM; 502265236Sken } 503265236Sken 504265236Sken offset += alignment; 505265236Sken entry->buf_count++; 506265236Sken byte_count += PAGE_SIZE << page_order; 507265236Sken } 508265236Sken 509265236Sken DRM_DEBUG("byte_count: %d\n", byte_count); 510265236Sken 511265236Sken temp_buflist = realloc(dma->buflist, 512265236Sken (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 513265236Sken DRM_MEM_BUFS, M_NOWAIT); 514265236Sken if (temp_buflist == NULL) { 515265236Sken /* Free the entry because it isn't valid */ 516265236Sken drm_cleanup_buf_error(dev, entry); 517265236Sken return ENOMEM; 518265236Sken } 519265236Sken dma->buflist = temp_buflist; 520265236Sken 521265236Sken for (i = 0; i < entry->buf_count; i++) { 522265236Sken dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 523265236Sken } 524265236Sken 525265236Sken dma->buf_count += entry->buf_count; 526265236Sken dma->byte_count += byte_count; 527265236Sken 528265236Sken DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 529265236Sken DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 530265236Sken 531265236Sken request->count = entry->buf_count; 532265236Sken request->size = size; 533265236Sken 534265236Sken dma->flags = _DRM_DMA_USE_AGP; 535265236Sken 536265236Sken return 0; 537265236Sken} 538265236Sken 539265236Skenstatic int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 540265236Sken{ 541265236Sken drm_device_dma_t *dma = dev->dma; 542265236Sken int count; 543265236Sken int order; 544265236Sken int size; 545265236Sken int total; 546265236Sken int page_order; 547265236Sken drm_buf_entry_t *entry; 548265236Sken drm_buf_t *buf; 549265236Sken int alignment; 550265236Sken unsigned long offset; 551265236Sken int i; 552265236Sken int byte_count; 553265236Sken int page_count; 554265236Sken unsigned long *temp_pagelist; 555265236Sken drm_buf_t **temp_buflist; 556265236Sken 557265236Sken count = request->count; 558265236Sken order = drm_order(request->size); 559265236Sken size = 1 << order; 560265236Sken 561265236Sken DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", 562265236Sken request->count, request->size, size, order); 563265236Sken 564265236Sken alignment = (request->flags & _DRM_PAGE_ALIGN) 565265236Sken ? round_page(size) : size; 566265236Sken page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 567265236Sken total = PAGE_SIZE << page_order; 568265236Sken 569265236Sken entry = &dma->bufs[order]; 570265236Sken 571265236Sken entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 572265236Sken M_NOWAIT | M_ZERO); 573265236Sken entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, 574265236Sken M_NOWAIT | M_ZERO); 575265236Sken 576265236Sken /* Keep the original pagelist until we know all the allocations 577265236Sken * have succeeded 578265236Sken */ 579265236Sken temp_pagelist = malloc((dma->page_count + (count << page_order)) * 580265236Sken sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT); 581265236Sken 582265236Sken if (entry->buflist == NULL || entry->seglist == NULL || 583265236Sken temp_pagelist == NULL) { 584265236Sken free(temp_pagelist, DRM_MEM_PAGES); 585265236Sken free(entry->seglist, DRM_MEM_SEGS); 586265236Sken free(entry->buflist, DRM_MEM_BUFS); 587265236Sken return ENOMEM; 588265236Sken } 589265236Sken 590265236Sken memcpy(temp_pagelist, dma->pagelist, dma->page_count * 591265236Sken sizeof(*dma->pagelist)); 592265236Sken 593265236Sken DRM_DEBUG("pagelist: %d entries\n", 594265236Sken dma->page_count + (count << page_order)); 595265236Sken 596265236Sken entry->buf_size = size; 597265236Sken entry->page_order = page_order; 598265236Sken byte_count = 0; 599265236Sken page_count = 0; 600265236Sken 601265236Sken while (entry->buf_count < count) { 602265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 603265236Sken drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 604265236Sken 0xfffffffful); 605265236Sken DRM_SPINLOCK(&dev->dma_lock); 606265236Sken if (dmah == NULL) { 607265236Sken /* Set count correctly so we free the proper amount. */ 608265236Sken entry->buf_count = count; 609265236Sken entry->seg_count = count; 610265236Sken drm_cleanup_buf_error(dev, entry); 611265236Sken free(temp_pagelist, DRM_MEM_PAGES); 612265236Sken return ENOMEM; 613265236Sken } 614265236Sken 615265236Sken entry->seglist[entry->seg_count++] = dmah; 616265236Sken for (i = 0; i < (1 << page_order); i++) { 617265236Sken DRM_DEBUG("page %d @ %p\n", 618265236Sken dma->page_count + page_count, 619265236Sken (char *)dmah->vaddr + PAGE_SIZE * i); 620265236Sken temp_pagelist[dma->page_count + page_count++] = 621265236Sken (long)dmah->vaddr + PAGE_SIZE * i; 622265236Sken } 623265236Sken for (offset = 0; 624265236Sken offset + size <= total && entry->buf_count < count; 625265236Sken offset += alignment, ++entry->buf_count) { 626265236Sken buf = &entry->buflist[entry->buf_count]; 627265236Sken buf->idx = dma->buf_count + entry->buf_count; 628265236Sken buf->total = alignment; 629265236Sken buf->order = order; 630265236Sken buf->used = 0; 631265236Sken buf->offset = (dma->byte_count + byte_count + offset); 632265236Sken buf->address = ((char *)dmah->vaddr + offset); 633265236Sken buf->bus_address = dmah->busaddr + offset; 634265236Sken buf->next = NULL; 635265236Sken buf->pending = 0; 636265236Sken buf->file_priv = NULL; 637265236Sken 638265236Sken buf->dev_priv_size = dev->driver->buf_priv_size; 639265236Sken buf->dev_private = malloc(buf->dev_priv_size, 640265236Sken DRM_MEM_BUFS, M_NOWAIT | M_ZERO); 641265236Sken if (buf->dev_private == NULL) { 642265236Sken /* Set count correctly so we free the proper amount. */ 643265236Sken entry->buf_count = count; 644265236Sken entry->seg_count = count; 645265236Sken drm_cleanup_buf_error(dev, entry); 646265236Sken free(temp_pagelist, DRM_MEM_PAGES); 647265236Sken return ENOMEM; 648265236Sken } 649265236Sken 650265236Sken DRM_DEBUG("buffer %d @ %p\n", 651265236Sken entry->buf_count, buf->address); 652265236Sken } 653265236Sken byte_count += PAGE_SIZE << page_order; 654265236Sken } 655265236Sken 656265236Sken temp_buflist = realloc(dma->buflist, 657265236Sken (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 658265236Sken DRM_MEM_BUFS, M_NOWAIT); 659265236Sken if (temp_buflist == NULL) { 660265236Sken /* Free the entry because it isn't valid */ 661265236Sken drm_cleanup_buf_error(dev, entry); 662265236Sken free(temp_pagelist, DRM_MEM_PAGES); 663265236Sken return ENOMEM; 664265236Sken } 665265236Sken dma->buflist = temp_buflist; 666265236Sken 667265236Sken for (i = 0; i < entry->buf_count; i++) { 668265236Sken dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 669265236Sken } 670265236Sken 671265236Sken /* No allocations failed, so now we can replace the orginal pagelist 672265236Sken * with the new one. 673265236Sken */ 674265236Sken free(dma->pagelist, DRM_MEM_PAGES); 675265236Sken dma->pagelist = temp_pagelist; 676265236Sken 677265236Sken dma->buf_count += entry->buf_count; 678265236Sken dma->seg_count += entry->seg_count; 679265236Sken dma->page_count += entry->seg_count << page_order; 680265236Sken dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); 681265236Sken 682265236Sken request->count = entry->buf_count; 683265236Sken request->size = size; 684283990Sslm 685265236Sken return 0; 686265236Sken 687283990Sslm} 688265236Sken 689283990Sslmstatic int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 690283990Sslm{ 691265236Sken drm_device_dma_t *dma = dev->dma; 692265236Sken drm_buf_entry_t *entry; 693265236Sken drm_buf_t *buf; 694265236Sken unsigned long offset; 695265236Sken unsigned long agp_offset; 696265236Sken int count; 697265236Sken int order; 698265236Sken int size; 699265236Sken int alignment; 700265236Sken int page_order; 701265236Sken int total; 702265236Sken int byte_count; 703265236Sken int i; 704265236Sken drm_buf_t **temp_buflist; 705265236Sken 706265236Sken count = request->count; 707265236Sken order = drm_order(request->size); 708265236Sken size = 1 << order; 709265236Sken 710265236Sken alignment = (request->flags & _DRM_PAGE_ALIGN) 711265236Sken ? round_page(size) : size; 712265236Sken page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; 713265236Sken total = PAGE_SIZE << page_order; 714265236Sken 715265236Sken byte_count = 0; 716265236Sken agp_offset = request->agp_start; 717265236Sken 718265236Sken DRM_DEBUG("count: %d\n", count); 719265236Sken DRM_DEBUG("order: %d\n", order); 720265236Sken DRM_DEBUG("size: %d\n", size); 721265236Sken DRM_DEBUG("agp_offset: %ld\n", agp_offset); 722283990Sslm DRM_DEBUG("alignment: %d\n", alignment); 723283990Sslm DRM_DEBUG("page_order: %d\n", page_order); 724283990Sslm DRM_DEBUG("total: %d\n", total); 725265236Sken 726283990Sslm entry = &dma->bufs[order]; 727283990Sslm 728283990Sslm entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, 729283990Sslm M_NOWAIT | M_ZERO); 730283990Sslm if (entry->buflist == NULL) 731283990Sslm return ENOMEM; 732283990Sslm 733283990Sslm entry->buf_size = size; 734283990Sslm entry->page_order = page_order; 735283990Sslm 736283990Sslm offset = 0; 737283990Sslm 738283990Sslm while (entry->buf_count < count) { 739283990Sslm buf = &entry->buflist[entry->buf_count]; 740283990Sslm buf->idx = dma->buf_count + entry->buf_count; 741283990Sslm buf->total = alignment; 742283990Sslm buf->order = order; 743265236Sken buf->used = 0; 744283990Sslm 745265236Sken buf->offset = (dma->byte_count + offset); 746265236Sken buf->bus_address = agp_offset + offset; 747265236Sken buf->address = (void *)(agp_offset + offset + dev->sg->handle); 748265236Sken buf->next = NULL; 749265236Sken buf->pending = 0; 750265236Sken buf->file_priv = NULL; 751265236Sken 752265236Sken buf->dev_priv_size = dev->driver->buf_priv_size; 753265236Sken buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, 754265236Sken M_NOWAIT | M_ZERO); 755265236Sken if (buf->dev_private == NULL) { 756265236Sken /* Set count correctly so we free the proper amount. */ 757265236Sken entry->buf_count = count; 758283990Sslm drm_cleanup_buf_error(dev, entry); 759265236Sken return ENOMEM; 760265236Sken } 761265236Sken 762265236Sken DRM_DEBUG("buffer %d @ %p\n", 763265236Sken entry->buf_count, buf->address); 764265236Sken 765265236Sken offset += alignment; 766265236Sken entry->buf_count++; 767265236Sken byte_count += PAGE_SIZE << page_order; 768265236Sken } 769265236Sken 770265236Sken DRM_DEBUG("byte_count: %d\n", byte_count); 771265236Sken 772265236Sken temp_buflist = realloc(dma->buflist, 773265236Sken (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), 774265236Sken DRM_MEM_BUFS, M_NOWAIT); 775265236Sken if (temp_buflist == NULL) { 776265236Sken /* Free the entry because it isn't valid */ 777265236Sken drm_cleanup_buf_error(dev, entry); 778265236Sken return ENOMEM; 779265236Sken } 780265236Sken dma->buflist = temp_buflist; 781283990Sslm 782283990Sslm for (i = 0; i < entry->buf_count; i++) { 783283990Sslm dma->buflist[i + dma->buf_count] = &entry->buflist[i]; 784265236Sken } 785265236Sken 786265236Sken dma->buf_count += entry->buf_count; 787265236Sken dma->byte_count += byte_count; 788265236Sken 789265236Sken DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); 790265236Sken DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); 791265236Sken 792265236Sken request->count = entry->buf_count; 793265236Sken request->size = size; 794265236Sken 795265236Sken dma->flags = _DRM_DMA_USE_SG; 796265236Sken 797265236Sken return 0; 798265236Sken} 799265236Sken 800265236Skenint drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) 801265236Sken{ 802265236Sken int order, ret; 803283990Sslm 804265236Sken if (request->count < 0 || request->count > 4096) 805265236Sken return EINVAL; 806265236Sken 807265236Sken order = drm_order(request->size); 808283990Sslm if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 809265236Sken return EINVAL; 810265236Sken 811265236Sken DRM_SPINLOCK(&dev->dma_lock); 812266548Sken 813266548Sken /* No more allocations after first buffer-using ioctl. */ 814265236Sken if (dev->buf_use != 0) { 815265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 816265236Sken return EBUSY; 817265236Sken } 818283990Sslm /* No more than one allocation per order */ 819283990Sslm if (dev->dma->bufs[order].buf_count != 0) { 820283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 821283990Sslm return ENOMEM; 822283990Sslm } 823283990Sslm 824283990Sslm ret = drm_do_addbufs_agp(dev, request); 825283990Sslm 826283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 827283990Sslm 828283990Sslm return ret; 829283990Sslm} 830283990Sslm 831283990Sslmint drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) 832283990Sslm{ 833283990Sslm int order, ret; 834283990Sslm 835283990Sslm if (!DRM_SUSER(DRM_CURPROC)) 836283990Sslm return EACCES; 837283990Sslm 838283990Sslm if (request->count < 0 || request->count > 4096) 839283990Sslm return EINVAL; 840283990Sslm 841283990Sslm order = drm_order(request->size); 842283990Sslm if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 843283990Sslm return EINVAL; 844283990Sslm 845283990Sslm DRM_SPINLOCK(&dev->dma_lock); 846283990Sslm 847283990Sslm /* No more allocations after first buffer-using ioctl. */ 848283990Sslm if (dev->buf_use != 0) { 849283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 850283990Sslm return EBUSY; 851283990Sslm } 852265236Sken /* No more than one allocation per order */ 853283990Sslm if (dev->dma->bufs[order].buf_count != 0) { 854283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 855283990Sslm return ENOMEM; 856283990Sslm } 857283990Sslm 858283990Sslm ret = drm_do_addbufs_sg(dev, request); 859283990Sslm 860283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 861283990Sslm 862265236Sken return ret; 863265236Sken} 864265236Sken 865265236Skenint drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) 866265236Sken{ 867265236Sken int order, ret; 868283990Sslm 869265236Sken if (!DRM_SUSER(DRM_CURPROC)) 870265236Sken return EACCES; 871265236Sken 872265236Sken if (request->count < 0 || request->count > 4096) 873265236Sken return EINVAL; 874265236Sken 875265236Sken order = drm_order(request->size); 876265236Sken if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) 877265236Sken return EINVAL; 878265236Sken 879265236Sken DRM_SPINLOCK(&dev->dma_lock); 880265236Sken 881265236Sken /* No more allocations after first buffer-using ioctl. */ 882265236Sken if (dev->buf_use != 0) { 883265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 884265236Sken return EBUSY; 885265236Sken } 886265236Sken /* No more than one allocation per order */ 887265236Sken if (dev->dma->bufs[order].buf_count != 0) { 888283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 889283990Sslm return ENOMEM; 890283990Sslm } 891283990Sslm 892283990Sslm ret = drm_do_addbufs_pci(dev, request); 893283990Sslm 894283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 895283990Sslm 896283990Sslm return ret; 897283990Sslm} 898265236Sken 899265236Skenint drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 900265236Sken{ 901265236Sken struct drm_buf_desc *request = data; 902265236Sken int err; 903265236Sken 904265236Sken if (request->flags & _DRM_AGP_BUFFER) 905265236Sken err = drm_addbufs_agp(dev, request); 906265236Sken else if (request->flags & _DRM_SG_BUFFER) 907265236Sken err = drm_addbufs_sg(dev, request); 908265236Sken else 909265236Sken err = drm_addbufs_pci(dev, request); 910265236Sken 911265236Sken return err; 912265236Sken} 913265236Sken 914265236Skenint drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 915265236Sken{ 916265236Sken drm_device_dma_t *dma = dev->dma; 917265236Sken struct drm_buf_info *request = data; 918265236Sken int i; 919265236Sken int count; 920265236Sken int retcode = 0; 921265236Sken 922265236Sken DRM_SPINLOCK(&dev->dma_lock); 923265236Sken ++dev->buf_use; /* Can't allocate more after this call */ 924265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 925265236Sken 926265236Sken for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 927265236Sken if (dma->bufs[i].buf_count) 928265236Sken ++count; 929265236Sken } 930265236Sken 931265236Sken DRM_DEBUG("count = %d\n", count); 932265236Sken 933265236Sken if (request->count >= count) { 934265236Sken for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { 935265236Sken if (dma->bufs[i].buf_count) { 936265236Sken struct drm_buf_desc from; 937265236Sken 938265236Sken from.count = dma->bufs[i].buf_count; 939265236Sken from.size = dma->bufs[i].buf_size; 940265236Sken from.low_mark = dma->bufs[i].freelist.low_mark; 941265236Sken from.high_mark = dma->bufs[i].freelist.high_mark; 942265236Sken 943265236Sken if (DRM_COPY_TO_USER(&request->list[count], &from, 944265236Sken sizeof(struct drm_buf_desc)) != 0) { 945265236Sken retcode = EFAULT; 946283990Sslm break; 947283990Sslm } 948283990Sslm 949283990Sslm DRM_DEBUG("%d %d %d %d %d\n", 950265236Sken i, dma->bufs[i].buf_count, 951265236Sken dma->bufs[i].buf_size, 952265236Sken dma->bufs[i].freelist.low_mark, 953265236Sken dma->bufs[i].freelist.high_mark); 954265236Sken ++count; 955265236Sken } 956265236Sken } 957265236Sken } 958265236Sken request->count = count; 959265236Sken 960265236Sken return retcode; 961265236Sken} 962265236Sken 963265236Skenint drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 964265236Sken{ 965265236Sken drm_device_dma_t *dma = dev->dma; 966265236Sken struct drm_buf_desc *request = data; 967265236Sken int order; 968265236Sken 969265236Sken DRM_DEBUG("%d, %d, %d\n", 970265236Sken request->size, request->low_mark, request->high_mark); 971265236Sken 972265236Sken 973265236Sken order = drm_order(request->size); 974265236Sken if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || 975265236Sken request->low_mark < 0 || request->high_mark < 0) { 976265236Sken return EINVAL; 977265236Sken } 978265236Sken 979265236Sken DRM_SPINLOCK(&dev->dma_lock); 980265236Sken if (request->low_mark > dma->bufs[order].buf_count || 981265236Sken request->high_mark > dma->bufs[order].buf_count) { 982265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 983265236Sken return EINVAL; 984265236Sken } 985265236Sken 986265236Sken dma->bufs[order].freelist.low_mark = request->low_mark; 987265236Sken dma->bufs[order].freelist.high_mark = request->high_mark; 988265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 989283990Sslm 990283990Sslm return 0; 991283990Sslm} 992283990Sslm 993283990Sslmint drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 994283990Sslm{ 995283990Sslm drm_device_dma_t *dma = dev->dma; 996283990Sslm struct drm_buf_free *request = data; 997283990Sslm int i; 998283990Sslm int idx; 999283990Sslm drm_buf_t *buf; 1000265236Sken int retcode = 0; 1001283990Sslm 1002283990Sslm DRM_DEBUG("%d\n", request->count); 1003283990Sslm 1004283990Sslm DRM_SPINLOCK(&dev->dma_lock); 1005265236Sken for (i = 0; i < request->count; i++) { 1006265236Sken if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { 1007265236Sken retcode = EFAULT; 1008265236Sken break; 1009265236Sken } 1010265236Sken if (idx < 0 || idx >= dma->buf_count) { 1011283990Sslm DRM_ERROR("Index %d (of %d max)\n", 1012265236Sken idx, dma->buf_count - 1); 1013265236Sken retcode = EINVAL; 1014265236Sken break; 1015265236Sken } 1016265236Sken buf = dma->buflist[idx]; 1017265236Sken if (buf->file_priv != file_priv) { 1018265236Sken DRM_ERROR("Process %d freeing buffer not owned\n", 1019265236Sken DRM_CURRENTPID); 1020265236Sken retcode = EINVAL; 1021265236Sken break; 1022265236Sken } 1023265236Sken drm_free_buffer(dev, buf); 1024265236Sken } 1025265236Sken DRM_SPINUNLOCK(&dev->dma_lock); 1026265236Sken 1027283990Sslm return retcode; 1028283990Sslm} 1029283990Sslm 1030283990Sslmint drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 1031283990Sslm{ 1032283990Sslm drm_device_dma_t *dma = dev->dma; 1033283990Sslm int retcode = 0; 1034283990Sslm const int zero = 0; 1035283990Sslm vm_offset_t address; 1036283990Sslm struct vmspace *vms; 1037265236Sken vm_ooffset_t foff; 1038265236Sken vm_size_t size; 1039265236Sken vm_offset_t vaddr; 1040283990Sslm struct drm_buf_map *request = data; 1041283990Sslm int i; 1042283990Sslm 1043283990Sslm vms = DRM_CURPROC->td_proc->p_vmspace; 1044283990Sslm 1045283990Sslm DRM_SPINLOCK(&dev->dma_lock); 1046283990Sslm dev->buf_use++; /* Can't allocate more after this call */ 1047283990Sslm DRM_SPINUNLOCK(&dev->dma_lock); 1048283990Sslm 1049283990Sslm if (request->count < dma->buf_count) 1050283990Sslm goto done; 1051283990Sslm 1052283990Sslm if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || 1053283990Sslm (drm_core_check_feature(dev, DRIVER_SG) && 1054283990Sslm (dma->flags & _DRM_DMA_USE_SG))) { 1055283990Sslm drm_local_map_t *map = dev->agp_buffer_map; 1056283990Sslm 1057283990Sslm if (map == NULL) { 1058283990Sslm retcode = EINVAL; 1059283990Sslm goto done; 1060283990Sslm } 1061283990Sslm size = round_page(map->size); 1062283990Sslm foff = (unsigned long)map->handle; 1063283990Sslm } else { 1064283990Sslm size = round_page(dma->byte_count), 1065283990Sslm foff = 0; 1066283990Sslm } 1067283990Sslm 1068283990Sslm vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); 1069283990Sslm#if __FreeBSD_version >= 600023 1070283990Sslm retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1071283990Sslm VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, 1072283990Sslm dev->devnode, foff); 1073283990Sslm#else 1074283990Sslm retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, 1075283990Sslm VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, 1076283990Sslm SLIST_FIRST(&dev->devnode->si_hlist), foff); 1077283990Sslm#endif 1078283990Sslm if (retcode) 1079283990Sslm goto done; 1080283990Sslm 1081283990Sslm request->virtual = (void *)vaddr; 1082283990Sslm 1083283990Sslm for (i = 0; i < dma->buf_count; i++) { 1084283990Sslm if (DRM_COPY_TO_USER(&request->list[i].idx, 1085283990Sslm &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { 1086283990Sslm retcode = EFAULT; 1087265236Sken goto done; 1088265236Sken } 1089265236Sken if (DRM_COPY_TO_USER(&request->list[i].total, 1090265236Sken &dma->buflist[i]->total, sizeof(request->list[0].total))) { 1091265236Sken retcode = EFAULT; 1092265236Sken goto done; 1093265236Sken } 1094265236Sken if (DRM_COPY_TO_USER(&request->list[i].used, &zero, 1095265236Sken sizeof(zero))) { 1096265236Sken retcode = EFAULT; 1097265236Sken goto done; 1098265236Sken } 1099265236Sken address = vaddr + dma->buflist[i]->offset; /* *** */ 1100265236Sken if (DRM_COPY_TO_USER(&request->list[i].address, &address, 1101265236Sken sizeof(address))) { 1102265236Sken retcode = EFAULT; 1103265236Sken goto done; 1104265236Sken } 1105265236Sken } 1106265236Sken 1107265236Sken done: 1108265236Sken request->count = dma->buf_count; 1109265236Sken 1110265236Sken DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); 1111265236Sken 1112265236Sken return retcode; 1113265236Sken} 1114265236Sken 1115265236Sken/* 1116265236Sken * Compute order. Can be made faster. 1117265236Sken */ 1118265236Skenint drm_order(unsigned long size) 1119265236Sken{ 1120265236Sken int order; 1121265236Sken 1122265236Sken if (size == 0) 1123265236Sken return 0; 1124265236Sken 1125265236Sken order = flsl(size) - 1; 1126265236Sken if (size & ~(1ul << order)) 1127265236Sken ++order; 1128265236Sken 1129266548Sken return order; 1130266548Sken} 1131265236Sken