xref: /dragonfly/sys/dev/drm/drm_vm.c (revision 99dd49c5)
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 "dev/drm/drmP.h"
29 #include "dev/drm/drm.h"
30 
31 int drm_mmap(struct dev_mmap_args *ap)
32 {
33 	struct cdev *kdev = ap->a_head.a_dev;
34 	vm_offset_t offset = ap->a_offset;
35 	struct drm_device *dev = drm_get_device_from_kdev(kdev);
36 	struct drm_file *file_priv = NULL;
37 	drm_local_map_t *map;
38 	enum drm_map_type type;
39 	vm_paddr_t phys;
40 
41         DRM_LOCK();
42         file_priv = drm_find_file_by_proc(dev, DRM_CURPROC);
43         DRM_UNLOCK();
44 
45         if (file_priv == NULL) {
46                 DRM_ERROR("can't find authenticator\n");
47                 return EINVAL;
48         }
49 
50         if (!file_priv->authenticated)
51                 return EACCES;
52 
53 	if (dev->dma && offset < ptoa(dev->dma->page_count)) {
54 		drm_device_dma_t *dma = dev->dma;
55 
56 		DRM_SPINLOCK(&dev->dma_lock);
57 
58 		if (dma->pagelist != NULL) {
59 			unsigned long page = offset >> PAGE_SHIFT;
60 			unsigned long phys = dma->pagelist[page];
61 			ap->a_result = atop(phys);
62 			DRM_SPINUNLOCK(&dev->dma_lock);
63 			return 0;
64 		} else {
65 			DRM_SPINUNLOCK(&dev->dma_lock);
66 			return -1;
67 		}
68 	}
69 
70 				/* A sequential search of a linked list is
71 				   fine here because: 1) there will only be
72 				   about 5-10 entries in the list and, 2) a
73 				   DRI client only has to do this mapping
74 				   once, so it doesn't have to be optimized
75 				   for performance, even if the list was a
76 				   bit longer. */
77 	DRM_LOCK();
78 	TAILQ_FOREACH(map, &dev->maplist, link) {
79 		if (offset >= map->offset && offset < map->offset + map->size)
80 			break;
81 	}
82 
83 	if (map == NULL) {
84 		DRM_DEBUG("Can't find map, requested offset = %016lx\n",
85 		    (unsigned long)offset);
86 		TAILQ_FOREACH(map, &dev->maplist, link) {
87 			DRM_DEBUG("map offset = %016lx, handle = %016lx\n",
88 			    (unsigned long)map->offset,
89 			    (unsigned long)map->handle);
90 		}
91 		DRM_UNLOCK();
92 		return -1;
93 	}
94 	if (((map->flags&_DRM_RESTRICTED) && !DRM_SUSER(DRM_CURPROC))) {
95 		DRM_UNLOCK();
96 		DRM_DEBUG("restricted map\n");
97 		return -1;
98 	}
99 	type = map->type;
100 	DRM_UNLOCK();
101 
102 	switch (type) {
103 	case _DRM_FRAME_BUFFER:
104 	case _DRM_REGISTERS:
105 	case _DRM_AGP:
106 		phys = offset;
107 		break;
108 	case _DRM_CONSISTENT:
109 		phys = vtophys((char *)map->handle + (offset - map->offset));
110 		break;
111 	case _DRM_SCATTER_GATHER:
112 	case _DRM_SHM:
113 		phys = vtophys(offset);
114 		break;
115 	default:
116 		DRM_ERROR("bad map type %d\n", type);
117 		return -1;	/* This should never happen. */
118 	}
119 
120 	ap->a_result = atop(phys);
121 	return 0;
122 }
123 
124