Home | History | Annotate | Line # | Download | only in bsd-core
      1 /*-
      2  * Copyright 2003 Eric Anholt
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /** @file drm_vm.c
     25  * Support code for mmaping of DRM maps.
     26  */
     27 
     28 #include "drmP.h"
     29 #include "drm.h"
     30 
     31 #if defined(__FreeBSD__)
     32 int drm_mmap(struct cdev *kdev, vm_offset_t offset, vm_paddr_t *paddr,
     33     int prot)
     34 #elif   defined(__NetBSD__)
     35 paddr_t drm_mmap(dev_t kdev, off_t offset, int prot)
     36 #endif
     37 {
     38 	struct drm_device *dev = drm_get_device_from_kdev(kdev);
     39 	struct drm_file *file_priv = NULL;
     40 	drm_local_map_t *map;
     41 	enum drm_map_type type;
     42 #if defined(__FreeBSD__)
     43 	vm_paddr_t phys;
     44 	int error;
     45 #elif   defined(__NetBSD__)
     46 	paddr_t phys;
     47 	int flags = 0;
     48 #endif
     49 
     50 #if defined(__FreeBSD__)
     51 	/* d_mmap gets called twice, we can only reference file_priv during
     52 	 * the first call.  We need to assume that if error is EBADF the
     53 	 * call was succesful and the client is authenticated.
     54 	 */
     55 	error = devfs_get_cdevpriv((void **)&file_priv);
     56 	if (error == ENOENT) {
     57 		DRM_ERROR("Could not find authenticator!\n");
     58 		return EINVAL;
     59 	}
     60 #elif   defined(__NetBSD__)
     61 	DRM_LOCK();
     62 	file_priv = drm_find_file_by_proc(dev, DRM_CURPROC);
     63 	DRM_UNLOCK();
     64 	if (file_priv == NULL) {
     65 		DRM_ERROR("Could not find authenticator!\n");
     66 		return -1;
     67 	}
     68 #endif
     69 
     70 	if (file_priv && !file_priv->authenticated)
     71 #if defined(__NetBSD__)
     72 		return -1;
     73 #else
     74 		return EACCES;
     75 #endif
     76 
     77 	if (dev->dma && offset >= 0 && offset < ptoa(dev->dma->page_count)) {
     78 		drm_device_dma_t *dma = dev->dma;
     79 
     80 		DRM_SPINLOCK(&dev->dma_lock);
     81 
     82 		if (dma->pagelist != NULL) {
     83 			unsigned long page = offset >> PAGE_SHIFT;
     84 			unsigned long physaddr = dma->pagelist[page];
     85 
     86 			DRM_SPINUNLOCK(&dev->dma_lock);
     87 #if defined(__FreeBSD__)
     88 			*paddr = physaddr;
     89 			return 0;
     90 #elif   defined(__NetBSD__)
     91 			return atop(physaddr);
     92 #endif
     93 		} else {
     94 			DRM_SPINUNLOCK(&dev->dma_lock);
     95 			return -1;
     96 		}
     97 	}
     98 
     99 				/* A sequential search of a linked list is
    100 				   fine here because: 1) there will only be
    101 				   about 5-10 entries in the list and, 2) a
    102 				   DRI client only has to do this mapping
    103 				   once, so it doesn't have to be optimized
    104 				   for performance, even if the list was a
    105 				   bit longer. */
    106 	DRM_LOCK();
    107 	TAILQ_FOREACH(map, &dev->maplist, link) {
    108 		if (offset >= map->offset && offset < map->offset + map->size)
    109 			break;
    110 	}
    111 
    112 	if (map == NULL) {
    113 		DRM_DEBUG("Can't find map, requested offset = %" PRIx64 "\n",
    114 		    offset);
    115 		TAILQ_FOREACH(map, &dev->maplist, link) {
    116 			DRM_DEBUG("map offset = %016lx, handle = %016lx\n",
    117 			map->offset, (unsigned long)map->handle);
    118 		}
    119 		DRM_UNLOCK();
    120 		return -1;
    121 	}
    122 	if (((map->flags&_DRM_RESTRICTED) && !DRM_SUSER(DRM_CURPROC))) {
    123 		DRM_UNLOCK();
    124 		DRM_DEBUG("restricted map\n");
    125 		return -1;
    126 	}
    127 	type = map->type;
    128 	DRM_UNLOCK();
    129 
    130 	switch (type) {
    131 	case _DRM_FRAME_BUFFER:
    132 	case _DRM_REGISTERS:
    133 	case _DRM_AGP:
    134 #if	defined(__NetBSD__)
    135 		flags = BUS_SPACE_MAP_LINEAR;
    136 		if (type == _DRM_FRAME_BUFFER || type == _DRM_AGP)
    137 			flags |= BUS_SPACE_MAP_PREFETCHABLE;
    138 		phys = bus_space_mmap(dev->pa.pa_memt, map->offset,
    139 				offset - map->offset, prot, flags);
    140 		if (phys == -1) {
    141 			DRM_ERROR("bus_space_mmap for %" PRIx64 " failed\n", offset);
    142 			return -1;
    143 		}
    144 		return phys;
    145 #else
    146 		phys = offset;
    147 #endif
    148 		break;
    149 	case _DRM_CONSISTENT:
    150 		phys = vtophys((vaddr_t)((char *)map->handle + (offset - map->offset)));
    151 		break;
    152 	case _DRM_SCATTER_GATHER:
    153 	case _DRM_SHM:
    154 		phys = vtophys(offset);
    155 		break;
    156 	default:
    157 		DRM_ERROR("bad map type %d\n", type);
    158 		return -1;	/* This should never happen. */
    159 	}
    160 
    161 #if defined(__FreeBSD__)
    162 	*paddr = phys;
    163 	return 0;
    164 #elif   defined(__NetBSD__)
    165 	return atop(phys);
    166 #endif
    167 }
    168 
    169