xref: /titanic_41/usr/src/uts/common/io/drm/drm_scatter.c (revision 672986541be54a7a471bb088e60780c37e371d7e)
1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /* BEGIN CSTYLED */
7 
8 /* drm_scatter.h -- IOCTLs to manage scatter/gather memory -*- linux-c -*-
9  * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com */
10 /*-
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice (including the next
22  * paragraph) shall be included in all copies or substantial portions of the
23  * Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *
33  * Authors:
34  *   Gareth Hughes <gareth@valinux.com>
35  *   Eric Anholt <anholt@FreeBSD.org>
36  *
37  */
38 /* END CSTYLED */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "drmP.h"
43 
44 #define	DEBUG_SCATTER 0
45 
46 void
47 drm_sg_cleanup(drm_sg_mem_t *entry)
48 {
49 	if (entry->busaddr) {
50 		drm_free(entry->busaddr,
51 		    entry->pages * sizeof (entry->busaddr),
52 		    DRM_MEM_PAGES);
53 		entry->busaddr = NULL;
54 	}
55 	if (entry->virtual) {
56 		ddi_umem_free(entry->sg_umem_cookie);
57 		entry->virtual = NULL;
58 	}
59 	if (entry) {
60 		drm_free(entry, sizeof (drm_sg_mem_t), DRM_MEM_SGLISTS);
61 	}
62 
63 }
64 
65 /*ARGSUSED*/
66 int
67 drm_sg_alloc(DRM_IOCTL_ARGS)
68 {
69 	DRM_DEVICE;
70 	drm_scatter_gather_t request;
71 	drm_sg_mem_t *entry;
72 	unsigned long pages;
73 
74 	DRM_DEBUG("%s\n", "drm_sg_alloc");
75 
76 	if (dev->sg)
77 		return (DRM_ERR(EINVAL));
78 
79 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
80 		drm_scatter_gather32_t request32;
81 
82 		DRM_COPY_FROM_USER_IOCTL(request32,
83 			(drm_scatter_gather32_t *)data,
84 			sizeof (drm_scatter_gather32_t));
85 		request.size = request32.size;
86 		request.handle = request32.handle;
87 	} else
88 		DRM_COPY_FROM_USER_IOCTL(request, (drm_scatter_gather_t *)data,
89 			sizeof (request));
90 
91 	entry = drm_alloc(sizeof (*entry), DRM_MEM_SGLISTS);
92 	if (!entry)
93 		return (DRM_ERR(ENOMEM));
94 
95 	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
96 	DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
97 
98 	entry->pages = pages;
99 
100 	entry->busaddr = drm_alloc(pages * sizeof (*entry->busaddr),
101 			DRM_MEM_PAGES);
102 
103 	if (!entry->busaddr) {
104 		drm_sg_cleanup(entry);
105 		return (DRM_ERR(ENOMEM));
106 	}
107 
108 	(void) memset((void *)entry->busaddr, 0,
109 	    pages * sizeof (*entry->busaddr));
110 
111 	entry->virtual = ddi_umem_alloc((size_t)(pages << PAGE_SHIFT),
112 			DDI_UMEM_SLEEP, &entry->sg_umem_cookie);
113 	if (!entry->virtual) {
114 		drm_sg_cleanup(entry);
115 		return (DRM_ERR(ENOMEM));
116 	}
117 
118 	entry->handle = (unsigned long)entry->virtual;
119 
120 	DRM_DEBUG("drm_sg_alloc: handle  = %08lx\n", entry->handle);
121 	DRM_DEBUG("drm_sg_alloc: virtual = %p\n", entry->virtual);
122 
123 	request.handle = entry->handle;
124 
125 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
126 		drm_scatter_gather32_t data32;
127 
128 		data32.size = request.size;
129 		data32.handle = request.handle;
130 
131 		DRM_COPY_TO_USER_IOCTL((drm_scatter_gather32_t *)data,
132 			data32,	sizeof (drm_scatter_gather32_t));
133 	} else
134 		DRM_COPY_TO_USER_IOCTL((drm_scatter_gather_t *)data,
135 			request,
136 			sizeof (request));
137 
138 	DRM_LOCK();
139 	if (dev->sg) {
140 		DRM_UNLOCK();
141 		drm_sg_cleanup(entry);
142 		return (DRM_ERR(EINVAL));
143 	}
144 	dev->sg = entry;
145 	DRM_UNLOCK();
146 
147 	return (0);
148 }
149 
150 /*ARGSUSED*/
151 int
152 drm_sg_free(DRM_IOCTL_ARGS)
153 {
154 	DRM_DEVICE;
155 	drm_scatter_gather_t request;
156 	drm_sg_mem_t *entry;
157 
158 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
159 		drm_scatter_gather32_t request32;
160 
161 		DRM_COPY_FROM_USER_IOCTL(request32,
162 			(drm_scatter_gather32_t *)data,
163 			sizeof (drm_scatter_gather32_t));
164 		request.size = request32.size;
165 		request.handle = request32.handle;
166 	} else
167 		DRM_COPY_FROM_USER_IOCTL(request, (drm_scatter_gather_t *)data,
168 			sizeof (request));
169 
170 	DRM_LOCK();
171 	entry = dev->sg;
172 	dev->sg = NULL;
173 	DRM_UNLOCK();
174 
175 	if (!entry || entry->handle != request.handle)
176 		return (DRM_ERR(EINVAL));
177 
178 	DRM_DEBUG("drm_sg_free: virtual  = %p\n", entry->virtual);
179 
180 	drm_sg_cleanup(entry);
181 
182 	return (0);
183 }
184