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