xref: /netbsd-src/sys/external/bsd/drm/dist/bsd-core/drm_vm.c (revision 767345987a6d305933d1ce6a09168dec65ad035b)
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__)
drm_mmap(struct cdev * kdev,vm_offset_t offset,vm_paddr_t * paddr,int prot)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