drm_vm.c revision 190170
171867Smsmith/*- 271867Smsmith * Copyright 2003 Eric Anholt 371867Smsmith * All Rights Reserved. 471867Smsmith * 5117521Snjl * Permission is hereby granted, free of charge, to any person obtaining a 671867Smsmith * copy of this software and associated documentation files (the "Software"), 771867Smsmith * to deal in the Software without restriction, including without limitation 871867Smsmith * the rights to use, copy, modify, merge, publish, distribute, sublicense, 971867Smsmith * and/or sell copies of the Software, and to permit persons to whom the 1071867Smsmith * Software is furnished to do so, subject to the following conditions: 1171867Smsmith * 1271867Smsmith * The above copyright notice and this permission notice (including the next 13114237Snjl * paragraph) shall be included in all copies or substantial portions of the 1471867Smsmith * Software. 1571867Smsmith * 1671867Smsmith * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1771867Smsmith * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1871867Smsmith * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1971867Smsmith * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 2071867Smsmith * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2171867Smsmith * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2271867Smsmith */ 2371867Smsmith 2471867Smsmith#include <sys/cdefs.h> 2571867Smsmith__FBSDID("$FreeBSD: head/sys/dev/drm/drm_vm.c 190170 2009-03-20 18:35:16Z rnoland $"); 2671867Smsmith 2771867Smsmith/** @file drm_vm.c 2871867Smsmith * Support code for mmaping of DRM maps. 2971867Smsmith */ 3071867Smsmith 3171867Smsmith#include "dev/drm/drmP.h" 3271867Smsmith#include "dev/drm/drm.h" 3371867Smsmith 3471867Smsmithint drm_mmap(struct cdev *kdev, vm_offset_t offset, vm_paddr_t *paddr, 3571867Smsmith int prot) 3671867Smsmith{ 3771867Smsmith struct drm_device *dev = drm_get_device_from_kdev(kdev); 3871867Smsmith struct drm_file *file_priv = NULL; 3971867Smsmith drm_local_map_t *map; 4071867Smsmith enum drm_map_type type; 4171867Smsmith vm_paddr_t phys; 4271867Smsmith int error; 4371867Smsmith 4471867Smsmith /* d_mmap gets called twice, we can only reference file_priv during 4571867Smsmith * the first call. We need to assume that if error is EBADF the 4671867Smsmith * call was succesful and the client is authenticated. 4771867Smsmith */ 4871867Smsmith error = devfs_get_cdevpriv((void **)&file_priv); 4971867Smsmith if (error == ENOENT) { 5071867Smsmith DRM_ERROR("Could not find authenticator!\n"); 5171867Smsmith return EINVAL; 5271867Smsmith } 5371867Smsmith 5471867Smsmith if (file_priv && !file_priv->authenticated) 5571867Smsmith return EACCES; 5671867Smsmith 5771867Smsmith if (dev->dma && offset < ptoa(dev->dma->page_count)) { 5871867Smsmith drm_device_dma_t *dma = dev->dma; 5971867Smsmith 6071867Smsmith DRM_SPINLOCK(&dev->dma_lock); 6171867Smsmith 6271867Smsmith if (dma->pagelist != NULL) { 6371867Smsmith unsigned long page = offset >> PAGE_SHIFT; 6471867Smsmith unsigned long phys = dma->pagelist[page]; 6571867Smsmith 6671867Smsmith DRM_SPINUNLOCK(&dev->dma_lock); 6771867Smsmith *paddr = phys; 6871867Smsmith return 0; 6971867Smsmith } else { 7071867Smsmith DRM_SPINUNLOCK(&dev->dma_lock); 7171867Smsmith return -1; 7271867Smsmith } 7371867Smsmith } 7471867Smsmith 7571867Smsmith /* A sequential search of a linked list is 7671867Smsmith fine here because: 1) there will only be 7771867Smsmith about 5-10 entries in the list and, 2) a 7871867Smsmith DRI client only has to do this mapping 7971867Smsmith once, so it doesn't have to be optimized 8071867Smsmith for performance, even if the list was a 8171867Smsmith bit longer. */ 8271867Smsmith DRM_LOCK(); 8371867Smsmith TAILQ_FOREACH(map, &dev->maplist, link) { 8471867Smsmith if (offset >= map->offset && offset < map->offset + map->size) 8571867Smsmith break; 8671867Smsmith } 8771867Smsmith 8871867Smsmith if (map == NULL) { 8971867Smsmith DRM_DEBUG("Can't find map, requested offset = %016lx\n", 9071867Smsmith (unsigned long)offset); 9171867Smsmith TAILQ_FOREACH(map, &dev->maplist, link) { 9271867Smsmith DRM_DEBUG("map offset = %016lx, handle = %016lx\n", 9371867Smsmith (unsigned long)map->offset, 9471867Smsmith (unsigned long)map->handle); 9571867Smsmith } 9671867Smsmith DRM_UNLOCK(); 9771867Smsmith return -1; 9871867Smsmith } 9971867Smsmith if (((map->flags&_DRM_RESTRICTED) && !DRM_SUSER(DRM_CURPROC))) { 10071867Smsmith DRM_UNLOCK(); 10171867Smsmith DRM_DEBUG("restricted map\n"); 10271867Smsmith return -1; 10371867Smsmith } 10471867Smsmith type = map->type; 10571867Smsmith DRM_UNLOCK(); 10671867Smsmith 10771867Smsmith switch (type) { 10871867Smsmith case _DRM_FRAME_BUFFER: 10971867Smsmith case _DRM_REGISTERS: 11071867Smsmith case _DRM_AGP: 11171867Smsmith phys = offset; 11271867Smsmith break; 11371867Smsmith case _DRM_CONSISTENT: 11471867Smsmith phys = vtophys((char *)map->handle + (offset - map->offset)); 11571867Smsmith break; 11671867Smsmith case _DRM_SCATTER_GATHER: 11771867Smsmith case _DRM_SHM: 11871867Smsmith phys = vtophys(offset); 11971867Smsmith break; 12077424Smsmith default: 12191116Smsmith DRM_ERROR("bad map type %d\n", type); 12271867Smsmith return -1; /* This should never happen. */ 12371867Smsmith } 12471867Smsmith 12571867Smsmith *paddr = phys; 12671867Smsmith return 0; 12771867Smsmith} 12871867Smsmith 12971867Smsmith